Получить (и отобразить) другие записи, которые соответствуют полю отношений ACF - PullRequest
2 голосов
/ 05 марта 2020

У меня есть поле ACF relationship с именем products. Это поле присутствует в настраиваемом типе записи с именем resources.

В resources у меня есть три блога под названием:

  • Блог 1
  • Блог 2
  • Блог 3

В блоге 1 для поля products установлено значение "Премиум". Блог 2 также имеет это поле, установленное на «Премиум».

Блог 3 имеет поле products, установленное на «Общий».

Я создал пользовательский модуль, который будет демонстрировать «сопутствующие товары» (блоги, соответствующие products). Например, если я в Blog 1 , я ожидаю увидеть заголовок Blog 2 в этом пользовательском модуле из-за совпадения поля products (они оба установлены на «Премиум»).

Если я нахожусь на Блог 3 , я ничего не вижу, потому что нет другого сообщения со значением products.

В настоящее время в моем пользовательском модуле (называемом «связанные продукты» для справки) у меня есть следующий код:

$posts = get_field('products');

if( $posts ):

    foreach( $posts as $post): 
        the_title();
    endforeach;

endif;

Теперь я нахожусь на Блог 1 и в Модуль "сопутствующие товары", я вижу: Premium напечатан один раз.

Он явно вытягивает данные, но я думаю, что это только для текущего поста (он показывает данные product для блога 1 ). Я проверил это, изменив products в Блоге 3 на «Премиум», и результаты остались прежними на странице, только «Премиум» напечатан один раз в посте.

Чего я пытаюсь достичь:

  • Получить другие сообщения того же типа product.
  • Извлечение данных из этих других сообщений (я хочу чтобы получить эти заголовки сообщений и отобразить их).

Ответы [ 3 ]

0 голосов
/ 09 марта 2020

ACF тип поля отношения сохраняет свои значения как serialized array в базе данных. Быстрый поиск по serialized array в базе данных как meta field невозможен для этого типа поля.

Я рекомендую перестроить и добавить собственный обработчик для обновления relation field в , ориентированный на скорость структура для получения значений.

Я предлагаю решение, основанное на перестройке этого типа поля с настраиваемой структурой для быстрого получения related_resources

( с использованием вашей собственной мета поля )

Коды фрагментов

1. Создание пользовательской структуры для существующих постов

//run this hook for build existing acf to speed search by meta structure
add_action( 'wp', 'theme_prefix_build_resources_products_meta' );
function theme_prefix_build_resources_products_meta() {
    /*  Visit the web site with theme-prefix-rebuild-resources-products GET  param for
        building existing resources to structure for searching*/
    // if needed - you could add permission checking and wp_nonce checking
    if ( ! isset( $_GET['theme-prefix-rebuild-resources-products'] ) ) {
        return;
    }

    wp_suspend_cache_addition( true ); // Prevent Fatal Error by Memory overflow if there is a lot of resources posts

    $args     = [
        'post_type'      => 'resources',
        'post_status'    => [ 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' ],
        'paged'          => 1,
        'posts_per_page' => 20,
    ];
    $meta_key = 'your-prefix-resource-product-id';
    while ( ! empty( $posts = get_posts( $args ) ) ) {
        foreach ( $posts as $post ) {
            $products = get_field( 'products', $post->ID );
            if ( empty( $products ) ) {
                continue;
            }

            delete_post_meta( $post->ID, $meta_key );

            foreach ( $products as $product ) {
                add_post_meta( $post->ID, $meta_key, $product->ID );
            }
        }

        $args['paged'] ++;
    }
}

2. Обновите поле для ускорения структуры

// store the relation field for searching structure
add_filter( 'acf/update_value', 'theme_prefix_acf_update_field', 10, 3 );

function theme_prefix_acf_update_field( $value, $post_id, $field ) {
    if ( ( 'products' !== $field['name'] ) || ( 'resources' !== get_post_type( $post_id ) ) ) {
        return $value;
    }

    $meta_key = 'your-prefix-resource-product-id';
    delete_post_meta( $post_id, $meta_key );

    $products_ids = $value;

    if ( empty( $products_ids ) ) {
        return $value;
    }

    foreach ( $products_ids as $product_id ) {
        add_post_meta( $post_id, $meta_key, $product_id );
    }

    return $value;
}

3. Получить связанные ресурсы

//You could get related_products in loop by calling theme_prefix_get_related_products( get_the_ID() ) ON Resource page
function theme_prefix_get_related_products( $resource_id ) {
    $resource_products    = get_field( 'products' );
    $related_products_ids = wp_list_pluck( $resource_products, 'ID' );

    $meta_key     = 'your-prefix-resource-product-id';
    $meta_queries = array_map(
        function ( $related_product_id ) use ( $meta_key ) {
            return [
                'key'     => $meta_key,
                'value'   => $related_product_id,
                'compare' => '=',
            ];
        },
        $related_products_ids
    );
    $args         = [
        'post_type'      => 'resources',
        'post_status'    => 'publish',
        'posts_per_page' => 5,
        'paged'          => 1,
        'orderby'        => 'rand',
        'meta_query'     => [ $meta_queries ]
    ];

    return get_posts( $args );
}
0 голосов
/ 12 марта 2020

То, что вы описываете, звучит просто.
Однако написанная вами строка кажется неправильной:

$posts = get_field('products');

Действительно, функция get_field() возвращает одно значение, а не коллекция постов.

Ниже приведен фрагмент, который извлекает все сообщения, для поля products которых установлено то же значение, что и для текущего сообщения:

$value = get_field('products');

$posts = get_posts(array(
    'numberposts'   => -1,
    'post_type'     => 'post',
    'meta_key'      => 'products',
    'meta_value'    => $value
));

Надеюсь, это поможет ...

0 голосов
/ 08 марта 2020

get_field('products') будет извлекать поле products из текущего сообщения, так что вы получите ожидаемый результат.

Если вы хотите показать все другие сообщения, которые имеют такое же значение в их * Поле 1005 *, вам нужно будет выбрать все сообщения и сравнить их products поля;

$thisPostsProductsField = get_field('products');
$allPosts = get_posts([
    'post_type' => 'resources',
    'numberposts' => -1,
    'post__not_in' => [get_the_ID()] # NOTE: Ignore the post we're on
]);
$relatedPosts = [];

foreach ($allPosts as $aPost) {
    $aPostsProductField = get_field('products', $aField->ID); # NOTE: The second argument to get_field() specifies from where to fetch the field, it defaults to the current post ID

    if ($aPostsProductField === $thisPostsProductsField) {
        $relatedPosts[] = $aPost;
    }
}

# $relatedPosts should now contain other posts of type "resources" that have the same "products" field
foreach ($relatedPosts as $post) {
    setup_postdata($post);

    the_title();
    the_content();
    the_post_thumbnail();
}

wp_reset_postdata();

Я предполагаю, что вы ограничили поле products отношением one после? В противном случае вам также потребуется l oop значение поля, и вам также нужно решить, достаточно ли в сообщении один продуктов исходного сообщения или в нем должно быть все продуктов исходного сообщения.

Редактировать: Вы можете вместо этого использовать meta_query, чтобы избежать необходимости извлекать каждый отдельный пост и сравнивать их поля;

$relatedPosts = get_posts([
    'post_type' => 'resources',
    'meta_query' => [
        [
            'key' => 'products',
            'value' => $thisPostsProductsField->ID,
            'compare' => '='
        ]
    ]
]);

Но это зависит от как ACF хранит поле products.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...