WordPress. Плагин «Похожие записи»

25.05.2019

Теги: CMSWeb-разработкаWordPressПлагин

Давайте создадим плагин, который для каждой записи будет выводить список похожих записей. Тут есть два варианта реализации:

  1. Вывести записи, которые находятся в тех же рубриках, что и текущая запись
  2. Вывести записи, которые отмечены теми же метками, что и текущая запись

Итак, создаем директорию tokmakov-related-posts, а внутри нее — файл tokmakov-related-posts.php. Привязываем к хуку the_content анонимную функцию, в которой и будет весь наш код. Мы «подцепим» (конкатенация) к контенту записи html-код списка похожих постов.

<?php
/*
Plugin Name: Похожие записи
Plugin URI: https://tokmakov.msk.ru
Description: Выводит список записей, связанных с текущей записью
Version: 1.0
Author: Евгений Токмаков
Author URI: https://tokmakov.msk.ru
*/

add_filter('the_content', function ($content) {

});

Первый способ

С помощью WP_Query получаем записи, которые находятся в тех же рубриках, что и текущая запись:

<?php
/*
Plugin Name: Похожие записи
Plugin URI: https://tokmakov.msk.ru
Description: Выводит список записей, связанных с текущей записью
Version: 1.0
Author: Евгений Токмаков
Author URI: https://tokmakov.msk.ru
*/

add_filter('the_content', function ($content) {

    if (!is_single()) {
        return $content;
    }

    // получаем идентификатор текущей записи
    $id = get_the_ID();
    // массив категорий, в которых расположена запись
    $categories = get_the_category($id);
    // массив идентификаторов категорий
    $ids = [];
    foreach ($categories as $category) {
        $ids[] = $category->cat_ID;
    }
    // получаем записи из этих категорий
    $query = new WP_Query([
        // выбираем только пять записей
        'posts_per_page' => 5,
        // из тех же категорий, что и текущая запись
        'category__in' => $ids,
        // текущую запись исключаем из выборки
        'post__not_in' => [$id],
    ]);
    // выводим полученные записи
    $related = '';
    if ($query->have_posts()) {
        $related = '<h4>Похожие записи:</h4>' . PHP_EOL;
        $related .= '<ul>' . PHP_EOL;
        while ($query->have_posts()) {
            $query->the_post();
            $title = get_the_title();
            $link = get_the_permalink();
            $related .= '<li><a href="' . $link . '">' . $title . '</a></li>' . PHP_EOL;
        }
        $related .=  '</ul>' . PHP_EOL;
        wp_reset_postdata();
    }

    return $content . $related;
});

Второй способ

С помощью WP_Query получаем записи, которые отмечены теми же метками, что и текущая запись:

<?php
/*
Plugin Name: Похожие записи
Plugin URI: https://tokmakov.msk.ru
Description: Выводит список записей, связанных с текущей записью
Version: 1.0
Author: Евгений Токмаков
Author URI: https://tokmakov.msk.ru
*/

add_filter('the_content', function ($content) {

    if (!is_single()) {
        return $content;
    }

    // получаем идентификатор текущей записи
    $id = get_the_ID();
    // массив тегов, с которыми связана запись
    $tags = wp_get_post_tags($id);
    // идентификаторы тегов, с которыми связана запись
    $ids = [];
    foreach ($tags as $tag) {
        $ids[] = $tag->term_id;
    }
    // получаем записи с такими же тегами
    $query = new WP_Query([
        // выбираем только пять записей
        'posts_per_page' => 5,
        // с теми же тегами, что у текущей записи
        'tag__in' => $ids,
        // текущую запись исключаем из выборки
        'post__not_in' => [$id],
    ]);
    // выводим полученные записи
    $related = '';
    if ($query->have_posts()) {
        $related = '<h4>Похожие записи:</h4>' . PHP_EOL;
        $related .= '<ul>' . PHP_EOL;
        while ($query->have_posts()) {
            $query->the_post();
            $title = get_the_title();
            $link = get_the_permalink();
            $related .= '<li><a href="' . $link . '">' . $title . '</a></li>' . PHP_EOL;
        }
        $related .=  '</ul>' . PHP_EOL;
        wp_reset_postdata();
    }

    return $content . $related;
});

Эти два способа можно объединить — получить записи, которые находятся в тех же рубриках и которые отмечены теми же метками, что и текущая запись:

$query = new WP_Query([
    // выбираем только пять записей
    'posts_per_page' => 5,
    // из тех же категорий, что и текущая запись
    'category__in' => $ctg_ids,
    // с теми же тегами, что у текущей записи
    'tag__in' => $tag_ids,
    // текущую запись исключаем из выборки
    'post__not_in' => [$id],
]);

Третий способ

При выборке записей с теми же метками есть существенный недостаток. В выборку могут попадать записи, у которых совпадает только одна метка. И при этом в выборку могут не попадать записи, у которых совпадают две или три метки. Условие построено так, что достаточно одного совпадения. Давайте это исправим — выбирать будем все записи, но отсортируем их по количеству совпадений меток. А потом покажем только первые пять:

<?php
/*
Plugin Name: Похожие записи
Plugin URI: https://tokmakov.msk.ru
Description: Выводит список записей, связанных с текущей записью
Version: 1.0
Author: Евгений Токмаков
Author URI: https://tokmakov.msk.ru
*/

add_filter('the_content', function ($content) {

    if (!is_single()) {
        return $content;
    }

    // получаем идентификатор текущей записи
    $id = get_the_ID();
    // массив тегов, с которыми связана запись
    $tags = wp_get_post_tags($id);

    /*
     * Для начала нам нужно получить все записи, связанные с
     * первым тегом, потом все записи, связанные со вторым
     * тегом и так далее. После этого узнать, у каких записей
     * больше совпадений по тегам с текущей записью.
     */
    $posts = []; // сюда будем сохранять полученные записи
    $relevance = []; // сюда будем записывать кол-во совпадений
    foreach ($tags as $tag) {
        // получаем записи, связанные с текущим тегом
        $query = new WP_Query([
            'posts_per_page' => -1,
            'tag__in' => [$tag->term_id],
            'post__not_in' => [$id],
        ]);
        foreach ($query->posts as $value) {
            // сохраняем полученные записи
            if (!isset($posts[$value->ID])) {
                $posts[$value->ID] = $value;
            }
            // записываем кол-во совпадений
            if (isset($relevance[$value->ID])) {
                $relevance[$value->ID] = $relevance[$value->ID] + 1;
            } else {
                $relevance[$value->ID] = 1;
            }
        }
    }
    /*
     * Теперь все записи, связанные с тегами текущей записи у
     * нас в массиве $posts, а сколько раз та или иная запись
     * встретилась при выборках — в массиве $relevance.
     */
    arsort($relevance);
    // нам нужно только пять самых релевантных записей
    $relevance = array_slice($relevance, 0, 5, true);
    $related = [];
    foreach ($relevance as $key => $value) {
        $related[] = $posts[$key];
    }
    unset($posts, $relevance);

    /*
     * Выводим полученные записи
     */
    $result = '';
    if (!empty($related)) {
        $result = '<h4>Похожие записи:</h4>' . PHP_EOL;
        $result .= '<ul>' . PHP_EOL;
        foreach ($related as $post) {
            $title = get_the_title($post->ID);
            $link = get_the_permalink($post->ID);
            $result .= '<li><a href="' . $link . '">' . $title . '</a></li>' . PHP_EOL;
        }
        $result .=  '</ul>' . PHP_EOL;
    }

    return $content . $result;
});

Поиск: CMS • Web-разработка • WordPress • Плагин

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.