Функциональность подобных, или связанных постов - часто желаемая функция для владельцев веб-сайтов WordPress. Небольшая сетка связанных статей под постом в блоге стала широко использоваться в первую очередь с точки зрения SEO и удержания пользователя на сайте. Это настолько распространено и эффективно, что многие сайты уже сложно представить без такого вида перекрестных ссылок.
Вы можете найти плагины для выполнения этой задачи. Их достаточное количество в WordPress, достаточно в поиске написать "Related Post" - и вуа-ля, устанавливайте тот, который подходит больше.
Но допустим, вам нужно реализовать такой дизайн, который ни один из плагинов вам не дает. Давайте разберемся, как создать надежную функциональность подобных постов с помощью самописного плагина. Он невелик и несложен, не использует большого количества настроек, но, возможно, вы давно хотели написать свой плагин!
С точки зрения реализации вы можете также можете писать код для темы.
Создание плагина
Основной файл плагина мы назовем mini-related-post.php и поместим его в папку с тем же названием mini-related-post в директорию wp-content/plugins. Если вы установили свой WordPress-сайт на локальный сервер, то сделать это будет несложно.
В файле в комментариях записываем все данные о плагине:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php /** * Plugin Name: Mini Related Post plugin * Plugin URI: https://www.your-site.com/ * Description: The plugin adds related posts after the single post article text. * Version: 0.1 * Author: your-name * Author URI: https://www.your-site.com/ * License: GPL2 **/ ?> |
Название плагина будет Mini Related Post. Думаю, что подставить свои данные в нужные поля описания вам не составит труда.
Основы функционала подобных записей
Прежде чем перейти к коду, давайте разберем, на чем основан вывод подобных записей. Мы используем запросы (query) и цикла WordPress (loop):
- Запрос WP_Query выберет записи WordPress из базы данных MySQL в соответствии с нашими инструкциями.
- Цикл выведет информацию о публикации на страницу. В нашем случае это будут такие вещи, как миниатюра публикации и заголовок, обернутые в ссылку на соответстующую запись.
- Код, который обрабатывает обе эти части, нужно будет как-то добавить в файл single.php любой темы. Для этого мы воспользуемся фильтром
add_filter( 'the_content')
Подобные записи будут отображаться под текстом полной записи в блоге.
Функция, добавляющая подобные записи после основного контента
Поскольку у нас плагин, а не тема, то мы должны будем "отфильтровать контент", т.е. воспользоваться функцией add_filter( 'the_content', 'mrp_add_related_post_view' )
и добавить записи только, если это одиночная страница (is_single()
).
Код добавляем после вводных комментариев о плагине.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
function mrp_add_related_post_view($content ) { $related_post_html=''; if(is_single()) { global $post; $catCurrent = wp_get_post_categories(get_the_ID()); // массив категорий данного поста $post_query_args = array( 'posts_per_page' => 3, // количество отображаемых записей 'post__not_in' => array($post->ID), // Все, кроме текущего поста 'orderby' => 'rand', // случайный выбор 'category__in' => $catCurrent //получить посты в той же категории, что и текущий пост ); // Формируем запрос $related_query = new WP_Query( $post_query_args ); // Запускаем цикл для отображения результата if ( $related_query->have_posts() ) { $related_post_html.='<h3 class="related-title">'.__('Related Posts', 'mrp').'</h3>'; $related_post_html.='<div class="related-posts-container">'; while ( $related_query->have_posts() ) : $related_query->the_post(); $related_post_html .='<div class="related-post">'; $related_post_html .='<a href="'.get_the_permalink() .'">'; if ( has_post_thumbnail() ) { $related_post_html .='<div class="related-thumbnail">'. get_the_post_thumbnail( get_the_ID(), 'medium' ) .'</div> '; } $related_post_html .= get_the_title(); $related_post_html .='</a></div>'; endwhile; $related_post_html .='</div>'; } else $related_post_html = '<p class="text-center">Sorry, no related articles to display.</p>'; // очищаем (сбрасываем) данные wp_reset_postdata(); } $content .=$related_post_html; return $content; } add_filter( 'the_content', 'mrp_add_related_post_view' ); |
Уже можно активировать плагин в соответствующем меню админки:
На данный момент, перейдя в любую запись, мы уже можем увидеть следующее отображение постов:
Чего не хватает? Правильно - стилей и расположения в 2 или 3 колонки.
Добавим стили
Все наши подобные записи будут выводится для просмотра одиночной записи. Стилей предполагается немного, поэтому особого смысла создавать отдельный файл и подключать его с помощью функции wp_enqueue_style() к нашему WordPress-сайту нет.
Мы встроим инлайновые стили, и только на страницу с полной версией поста, потому что нам еще важна и оптимизация загрузки сайта.
Поэтому мы внесем такой код в наш главный файл mini-related-post.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
add_action( 'wp_enqueue_scripts', 'mrp_wp_enqueue_inline_styles' ); function mrp_wp_enqueue_inline_styles(){ $styles = ' .related-title { padding: 15px 0; border-top: 1px solid #cdcdcd; margin-top: 15px; } .related-thumbnail{ height: 200px; overflow: hidden; } .related-thumbnail img{ width: 100%; height: 100%; object-fit: cover; transition: transform .5s; } .related-thumbnail:hover img{ transform: scale(1.1); } '; $key = 'mrp-styles'; if(is_single( )){ wp_register_style( $key, false, array(), true, true ); wp_add_inline_style( $key, $styles ); wp_enqueue_style( $key ); } } |
Сейчас блоки стали больше, появились эффекты увеличения картинки при наведении.
Добавляем настройки для плагина подобных записей
Нашему плагину все еще не хватает css-форматирования для колонок. Однако у пользователя вполне уже могут быть стили, которые разбивают контент на 2,3 и более колонок. Поэтому мы не будем выстраивать подобные посты в ряд, а зададим для этого настройки.
Поскольку изображения для записей могут быть какого угодно размера, неплохо было бы определить их, как небольшие, если уж пользователю предоставлено право выбирать количество колонок.
Ну, и заголовок неплохо было бы ввести на том языке, на котором удобнее пользователю, а не только на английском, как на скриншотах.
Поскольку создание настроек - процес довольно длительный с массой объяснений, как называть все страницы, блоки и опции, а хочется сделать все быстро, то мы используем генератор настроек и зальем его код в отдельный файл settings.php.
Переходим на сайт и указываем название плагина, название настроек, куда поместить эти настройки, а также все нужные нам поля и их тип.
Вот, что получилось с помощью генератора:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
<?php /** * Generated by the WordPress Option Page generator * at http://jeremyhixon.com/wp-tools/option-page/ */ class MiniRelatedPosts { private $mini_related_posts_options; public function __construct() { add_action( 'admin_menu', array( $this, 'mini_related_posts_add_plugin_page' ) ); add_action( 'admin_init', array( $this, 'mini_related_posts_page_init' ) ); } public function mini_related_posts_add_plugin_page() { add_posts_page( 'Mini Related Posts', // page_title 'Mini Related Posts', // menu_title 'manage_options', // capability 'mini-related-posts', // menu_slug array( $this, 'mini_related_posts_create_admin_page' ) // function ); } public function mini_related_posts_create_admin_page() { $this->mini_related_posts_options = get_option( 'mini_related_posts_option_name' ); ?> <div class="wrap"> <h2>Mini Related Posts</h2> <p>Main Settings</p> <?php settings_errors(); ?> <form method="post" action="options.php"> <?php settings_fields( 'mini_related_posts_option_group' ); do_settings_sections( 'mini-related-posts-admin' ); submit_button(); ?> </form> </div> <?php } public function mini_related_posts_page_init() { register_setting( 'mini_related_posts_option_group', // option_group 'mini_related_posts_option_name', // option_name array( $this, 'mini_related_posts_sanitize' ) // sanitize_callback ); add_settings_section( 'mini_related_posts_setting_section', // id 'Settings', // title array( $this, 'mini_related_posts_section_info' ), // callback 'mini-related-posts-admin' // page ); add_settings_field( 'title_0', // id 'Title', // title array( $this, 'title_0_callback' ), // callback 'mini-related-posts-admin', // page 'mini_related_posts_setting_section' // section ); add_settings_field( 'container_class_1', // id 'Container Class', // title array( $this, 'container_class_1_callback' ), // callback 'mini-related-posts-admin', // page 'mini_related_posts_setting_section' // section ); add_settings_field( 'column_class_2', // id 'Column Class', // title array( $this, 'column_class_2_callback' ), // callback 'mini-related-posts-admin', // page 'mini_related_posts_setting_section' // section ); add_settings_field( 'image_size_3', // id 'Image Size', // title array( $this, 'image_size_3_callback' ), // callback 'mini-related-posts-admin', // page 'mini_related_posts_setting_section' // section ); } public function mini_related_posts_sanitize($input) { $sanitary_values = array(); if ( isset( $input['title_0'] ) ) { $sanitary_values['title_0'] = sanitize_text_field( $input['title_0'] ); } if ( isset( $input['container_class_1'] ) ) { $sanitary_values['container_class_1'] = sanitize_text_field( $input['container_class_1'] ); } if ( isset( $input['column_class_2'] ) ) { $sanitary_values['column_class_2'] = sanitize_text_field( $input['column_class_2'] ); } if ( isset( $input['image_size_3'] ) ) { $sanitary_values['image_size_3'] = $input['image_size_3']; } return $sanitary_values; } public function mini_related_posts_section_info() { } public function title_0_callback() { printf( '<input class="regular-text" type="text" name="mini_related_posts_option_name[title_0]" id="title_0" value="%s">', isset( $this->mini_related_posts_options['title_0'] ) ? esc_attr( $this->mini_related_posts_options['title_0']) : '' ); } public function container_class_1_callback() { printf( '<input class="regular-text" type="text" name="mini_related_posts_option_name[container_class_1]" id="container_class_1" value="%s">', isset( $this->mini_related_posts_options['container_class_1'] ) ? esc_attr( $this->mini_related_posts_options['container_class_1']) : '' ); } public function column_class_2_callback() { printf( '<input class="regular-text" type="text" name="mini_related_posts_option_name[column_class_2]" id="column_class_2" value="%s">', isset( $this->mini_related_posts_options['column_class_2'] ) ? esc_attr( $this->mini_related_posts_options['column_class_2']) : '' ); } public function image_size_3_callback() { ?> <select name="mini_related_posts_option_name[image_size_3]" id="image_size_3"> <?php $selected = (isset( $this->mini_related_posts_options['image_size_3'] ) && $this->mini_related_posts_options['image_size_3'] === 'thumbnail') ? 'selected' : '' ; ?> <option <?php echo $selected; ?>>thumbnail</option> <?php $selected = (isset( $this->mini_related_posts_options['image_size_3'] ) && $this->mini_related_posts_options['image_size_3'] === 'medium') ? 'selected' : '' ; ?> <option <?php echo $selected; ?>>medium</option> </select> <?php } } if ( is_admin() ) $mini_related_posts = new MiniRelatedPosts(); /* * Retrieve this value with: * $mini_related_posts_options = get_option( 'mini_related_posts_option_name' ); // Array of All Options * $title_0 = $mini_related_posts_options['title_0']; // Title * $container_class_1 = $mini_related_posts_options['container_class_1']; // Container Class * $column_class_2 = $mini_related_posts_options['column_class_2']; // Column Class * $image_size_3 = $mini_related_posts_options['image_size_3']; // Image Size */ |
В самом низу есть тот код, который нам нужно добавить в основную функцию, чтоб изменить классы и заголовок в подобных записях.
Подключаем файл settings.php в коде файла mini-related-post.php (в примере мы укладываем его в папку inc плагина).
1 |
require_once('inc/settings.php'); |
Заполняем настройки, которые появились у нас в меню "Записи" в админке WordPress.
Формируем вывод подобных записей с настройками
Теперь мы можем получить функционал уже с использованием настроек.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
<?php /** * Plugin Name: Mini Related Post plugin * Plugin URI: https://www.your-site.com/ * Description: The plugin adds related posts after the single post article text.. * Version: 0.1 * Author: your-name * Author URI: https://www.your-site.com/ * License: GPL2 **/ require_once('inc/settings.php'); function mrp_add_related_post_view($content ) { $mini_related_posts_options = get_option( 'mini_related_posts_option_name' ); // Массив всех настроек $title = $mini_related_posts_options['title_0']; $title = empty($title) ? 'Related Posts': $title; // Заголовок $container_class = $mini_related_posts_options['container_class_1']; // Класс для всех связанных постов $column_class = $mini_related_posts_options['column_class_2']; // класс для колонок $image_size = $mini_related_posts_options['image_size_3']; // размер изображения // $place_for_related_posts = $mini_related_posts_options['place_for_related_posts_4']; $related_post_html=''; if(is_single()) { global $post; $catCurrent = wp_get_post_categories(get_the_ID()); // массив категорий данного поста $post_query_args = array( 'posts_per_page' => 3, // количество отображаемых записей 'post__not_in' => array($post->ID), // Все, кроме текущего поста 'orderby' => 'rand', // случайный выбор 'category__in' => $catCurrent //получить посты в той же категории, что и текущий пост ); // Формируем запрос $related_query = new WP_Query( $post_query_args ); // Запускаем цикл для отображения результата if ( $related_query->have_posts() ) { $related_post_html.='<h3 class="related-title">'._.$title..'</h3>'; $related_post_html.='<div class="related-posts-container '.$container_class.'">'; while ( $related_query->have_posts() ) : $related_query->the_post(); $related_post_html .='<div class="related-post '.$column_class.'">'; $related_post_html .='<a href="'.get_the_permalink() .'">'; if ( has_post_thumbnail() ) { $related_post_html .='<div class="related-thumbnail">'. get_the_post_thumbnail( get_the_ID(), $image_size ) .'</div> '; } $related_post_html .= get_the_title(); $related_post_html .='</a></div>'; endwhile; $related_post_html .='</div>'; } else $related_post_html = '<p class="text-center">Sorry, no related articles to display.</p>'; // очищаем (сбрасываем) данные wp_reset_postdata(); } $content .=$related_post_html; return $content; } add_filter( 'the_content', 'mrp_add_related_post_view' ); add_action( 'wp_enqueue_scripts', 'mrp_wp_enqueue_inline_styles' ); function mrp_wp_enqueue_inline_styles(){ $styles = ' .related-title { padding: 15px 0; border-top: 1px solid #cdcdcd; margin-top: 15px; } .related-thumbnail{ height: 200px; overflow: hidden; } .related-thumbnail img{ width: 100%; height: 100%; object-fit: cover; transition: transform .5s; } .related-thumbnail:hover img{ transform: scale(1.1); } '; $key = 'mrp-styles'; if(is_single( )){ wp_register_style( $key, false, array(), true, true ); wp_add_inline_style( $key, $styles ); wp_enqueue_style( $key ); } } |
Результат наших манипуляций с настройками для разных разрешений экранов:
Надеюсь, что у вас все получилось.