
Проста кнопка «Подобається» для сайту без плагіну
Мені поставили завдання організувати збір інформації щодо лояльністі користувачів до постів сайту «Проект 90». Така інформація використовується для ранжування постів за популярністю. Кнопка «Подобається» від соціальних мереж – один з найпростіших способів отримання такої інформації. Але функції соціальних мереж обов’язково вимагають процедуру реєстрації та авторизації, а це напевно відлякає користувача. Справа в тому, що основна аудиторія сайту «Проект 90» погано володіє навичками роботи за комп’ютером і в мережі інтернет. Тому кнопка “Подобається” повинна бути максимально схожа на аналогічний функціонал соціальних мереж і при цьому не вимагати окремої авторизації. Так само необхыдно додати мінімальний захист від накрутки і більш-менш адекватний лічільник лайків.
Як це реалізувати
Сайт «Проект 90» працює на CSM WordPress, тому в розробці враховані особливості саме цієї системи.
Детальніше про тему, яка використовується на сайті проекту: WordPress-тема для сайту присвяченого заходу.
Я не прихильник використання окремого плагіна для простих завдань, тому кнопка “Подобається” додана в код WordPress-тему, а не підключена окремо.
Для коректного збору інформації про лайки потрібна ідентифікація користувача, так як вона дозволяє уникнути повторного голосування. Ідентифікатор формується за допомогою JavaScript в публічній частині сайту на основі даних про браузер і поточний час. Дані зберігаються в локальному сховищі браузера (детальніше про localStorage). При натисканні на кнопку «Подобається» ідентифікатор користувача передається на сервер і записується в базу даних.
Облік «лайків» на сервері ведеться за допомогою метаполів таблиці wp_postmeta
. Щоб не засмічувати базу даних метаполя видаляються при деактивації теми.
meta_id | post_id | meta_key | meta_value |
---|---|---|---|
auto | $post_id | 'liked' | $user_id |
Щоб зменшити кількість запитів на сервер в локальному сховищі браузера створюється масив ідентифікаторів вподобаних постів. При завантаженні сторінки, за допомогою JavaScript порівнюється список ідентифікаторів завантажених постів зі списком вподобаних. На основі цього порівняння додаються класи-стани для кнопок.
Після натискання на кнопку «Мені подобається» на сервер відправляється ідентифікатор користувача і ідентифікатор вподобаного запису. У разі успіху запису додається нове метапол з ідентифікатором користувача. При повторному лайці метапол видаляється. Кількість лайків поста дорівнює кількості метапол. У браузер повертається інформація про скоєну дію і кількість лайків.

Серверна частина
Весь php-код підключається в файлі functions.php
теми.
Формування коду кнопки “Подобається”
Формування html-коду кнопки «Подобається» доцільно винести в окрему функцію, яку в подальшому буде зручно використовувати. Ідентифікатор поста і кількість лайків зберігаються в data-аттрибутах кнопки. При натисканні кнопки JavaScript код підхоплює ідентифікатор і передає його на сервер.
function get_like_button( $post_id = false ) {
if ( ! $post_id ) {
$post_id = get_the_ID();
}
$count = count( get_post_meta( $post_id, '_liked', false ) );
return sprintf(
'<button class="like" data-like-id="%1$s" data-liked-count="%2$s"><span class="sr-only">%3$s</span></button>',
$post_id,
( empty( $count ) ) ? '' : esc_attr( $count ),
__( 'Поставить лайк', THEME_TEXTDOMAIN )
);
}
Обробка ajax запиту
Інформацію про натискання кнопки “Подобається” сервер отримує через AJAX. Для обробки такого запиту від всіх користувачів потрібно скористатися хукамі wp_ajax_(action)
і wp_ajax_nopriv_(action)
.
Детальніше про використання AJAX на сайті: “Ajax в WordPress“.
function like_processing() {
// проверяем код безопасности
if ( isset( $_GET[ 'security' ] ) && wp_verify_nonce( $_GET[ 'security' ], 'liked' ) ) {
// проверяем есть ли идентификатор поста и пользователя, без этих параметров можно дальше не продолжать
if ( isset( $_GET[ 'post_id' ] ) && ! empty( $_GET[ 'client_id' ] ) && ! empty( $_GET[ 'client_id' ] ) ) {
// очищаем идентификатор поста
$post_id = sanitize_key( $_GET[ 'post_id' ] );
// очищаем идентификатор пользователя
$client_id = sanitize_text_field( $_GET[ 'client_id' ] );
// получаем массив лайком для текущего поста
$liked = get_post_meta( $post_id, '_liked', false );
// инициализируем переменную для ответа браузеру пользователя
$action = '';
// провверяем ставил ли уже пользователь лайк текущему посту
if ( in_array( $client_id, $liked ) ) {
// усли ставил, то удаляем лайк, и присваиваем соответствующий ответ для переменной $action
delete_post_meta( $post_id, '_liked', $client_id );
$action = 'delete';
} else {
// добавляем новый лайт и ответ в переменной $action
add_post_meta( sanitize_key( $_GET[ 'post_id' ] ), '_liked', $client_id, false );
$action = 'add';
}
// формируем ответ браузеру пользователя
// будет передано количество поставленных лайков и информация
// о выполненном на сервере действии (добавили или удалили)
wp_send_json_success( array(
'action' => $action,
'count' => count( get_post_meta( $post_id, '_liked', false ) ),
) );
}
}
// обравыем работу скрипта
wp_die();
}
// цепляем хуки, action в нашем случае равен 'liked'
add_action( 'wp_ajax_liked', 'like_processing' );
add_action( 'wp_ajax_nopriv_liked', 'like_processing' );
Підключаємо js-скрипт лицьової частини сайту
Для можливості використання AJAX в лицьовій частині сайту треба створити js-змінну ajaxurl. Зробимо це за допомогою функції wp_enqueue_script
. Так само передамо і код безпеки (nonce-код), який формується за допомогою функції wp_create_nonce
. Код безпеки допоможе відсіяти частину спамерських ботів. Для перевірки інших дій неавторизованих користувачів його використовувати безглуздо.
function liked_scripts() {
wp_enqueue_script( 'liked', THEME_URL . 'scripts/liked.js', array( 'jquery' ), THEME_VERSION, true );
wp_localize_script( 'liked', 'ThemeLiked', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'liked' => wp_create_nonce( 'liked' ),
) );
}
add_action( 'wp_enqueue_scripts', 'liked_scripts' );
Використання кнопки в WordPress-темі
Для додавання кнопки до посту потрібно викликати функцію get_like_button ( $post_id )
з параметром ідентифікатор поста. У циклі WordPress цей параметр $post_id є не обов’язковим.
if ( have_post() ) {
while ( have_post() ) {
the_post();
the_title();
the_excerpt();
echo get_like_button( get_the_ID() );
}
}
Клієнтська частина
Клієнтська частина коду знаходиться в файлі liked.js
. У ньому формується ідентифікатор користувача, встановлюються класи-стани кнопок “Подобається” та формується запит на сервер. Ідентифікатор користувача це по суті hash-код сформований з рядка з інформацією про браузер, поточну дату та час.
jQuery( document ).ready( function () {
// функция в которой отправляется AJAX запрос на сервер
function set_like( $button ) {
// получаем идентификатор поста (хранится в атрибуте кнопки)
var post_id = $button.attr( 'data-like-id' );
// создаём AJAX запрос на сервер
jQuery.ajax( {
type: 'GET',
url: ThemeLiked.ajaxurl,
data: {
action: 'liked',
security: ThemeLiked.liked,
post_id: post_id,
client_id: client_id,
},
// перед отправкой запроса добавляем класс для индикации загрузки
beforeSend: function () {
$button.addClass( 'loading' );
},
// действия в случае успешного запроса
success: function ( answer ) {
if ( answer.data.action == 'add' ) {
liked[ liked.length ] = Number( post_id );
$button.addClass( 'liked' );
} else {
liked.splice( liked.indexOf( Number( post_id ) ), 1 );
$button.removeClass( 'liked' );
}
$button.attr( 'data-liked-count', answer.data.count );
},
error: function ( answer ) {
console.log( answer );
},
// после обработки запроса убираем класс индикации загрузки
} ).then( function () {
window.localStorage.setItem( 'liked', JSON.stringify( liked ) );
$button.removeClass( 'loading' );
} );
}
// функция для формирования хеш-кода
String.prototype.hashCode = function() {
var hash = 0, i, chr;
if ( this.length === 0) return hash;
for (i = 0; i < this.length; i++) {
chr = this.charCodeAt(i);
hash = ( (hash << 5 ) - hash ) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
var date = new Date();
var client_id = window.localStorage.getItem( 'client_id' );
var liked;
// если идентификатор клиента не задан, то формируем его
if ( client_id == null ) {
client_id = new String( navigator.userAgen + ' ' + date.toString() + ' ' ).hashCode();
window.localStorage.setItem( 'client_id', client_id );
}
// получаем массив понравившихся постов
if ( window.localStorage.getItem( 'liked' ) == null ) {
liked = [];
window.localStorage.setItem( 'liked', JSON.stringify( liked ) )
} else {
liked = JSON.parse( window.localStorage.getItem( 'liked' ) );
}
// устанавливаем статус "Понравился" выбранным кнопкам
jQuery( '[data-like-id]' ).each( function ( index, button ) {
var $button = jQuery( button );
if ( liked.includes( Number( $button.attr( 'data-like-id' ) ) ) ) {
$button.addClass( 'liked' );
if ( $button.attr( 'data-liked-count' ).length == 0 || $button.attr( 'data-liked-count' ) == 0 ) {
set_like( $button );
}
}
} );
// утановка событие на клик по кнопкам "Нравится"
jQuery( 'body' ).on( 'click', '[data-like-id]:not( .loading )', function ( e ) {
e.preventDefault();
set_like( jQuery( this ) );
} );
} );
Стильове оформлення
Кнопка “Подобається” може знаходитися в трьох станах, це: “лайк не поставлений” (немає класу), “передача даних на сервер” (.loading
) і “лайк поставлений” (.liked
). Стан візуалізуються за допомогою класів, які додає JavaScript код. Для классу .liked
використано css-анімацію.
У всіх трьох класах використовуються svg-іконки, для їх підбору зручно використовувати сервіс FlatIcon. Щоб уникнути збільшення часу завантаження при скачуванні додаткових файлів і кешувати іконки разом з іншим css кодом, іконки конвертовані в BASE64 і додані в css як текст.
@keyframes like-loading {
from {
transform: rotate( 0deg );
}
to {
transform: rotate( 350deg );
}
}
.like {
display: inline-block;
border: none;
background-color: transparent;
&::before {
content: '';
width: 1em;
height: 1em;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
max-width: 512px;
max-height: 512px;
background-image: url( 'data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIC0yOCA1MTIuMDAxIDUxMiIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48cGF0aCBkPSJtMjU2IDQ1NS41MTU2MjVjLTcuMjg5MDYyIDAtMTQuMzE2NDA2LTIuNjQwNjI1LTE5Ljc5Mjk2OS03LjQzNzUtMjAuNjgzNTkzLTE4LjA4NTkzNy00MC42MjUtMzUuMDgyMDMxLTU4LjIxODc1LTUwLjA3NDIxOWwtLjA4OTg0My0uMDc4MTI1Yy01MS41ODIwMzItNDMuOTU3MDMxLTk2LjEyNS04MS45MTc5NjktMTI3LjExNzE4OC0xMTkuMzEyNS0zNC42NDQ1MzEtNDEuODA0Njg3LTUwLjc4MTI1LTgxLjQ0MTQwNi01MC43ODEyNS0xMjQuNzQyMTg3IDAtNDIuMDcwMzEzIDE0LjQyNTc4MS04MC44ODI4MTMgNDAuNjE3MTg4LTEwOS4yOTI5NjkgMjYuNTAzOTA2LTI4Ljc0NjA5NCA2Mi44NzEwOTMtNDQuNTc4MTI1IDEwMi40MTQwNjItNDQuNTc4MTI1IDI5LjU1NDY4OCAwIDU2LjYyMTA5NCA5LjM0Mzc1IDgwLjQ0NTMxMiAyNy43Njk1MzEgMTIuMDIzNDM4IDkuMzAwNzgxIDIyLjkyMTg3NiAyMC42ODM1OTQgMzIuNTIzNDM4IDMzLjk2MDkzOCA5LjYwNTQ2OS0xMy4yNzczNDQgMjAuNS0yNC42NjAxNTcgMzIuNTI3MzQ0LTMzLjk2MDkzOCAyMy44MjQyMTgtMTguNDI1NzgxIDUwLjg5MDYyNS0yNy43Njk1MzEgODAuNDQ1MzEyLTI3Ljc2OTUzMSAzOS41MzkwNjMgMCA3NS45MTAxNTYgMTUuODMyMDMxIDEwMi40MTQwNjMgNDQuNTc4MTI1IDI2LjE5MTQwNiAyOC40MTAxNTYgNDAuNjEzMjgxIDY3LjIyMjY1NiA0MC42MTMyODEgMTA5LjI5Mjk2OSAwIDQzLjMwMDc4MS0xNi4xMzI4MTIgODIuOTM3NS01MC43NzczNDQgMTI0LjczODI4MS0zMC45OTIxODcgMzcuMzk4NDM3LTc1LjUzMTI1IDc1LjM1NTQ2OS0xMjcuMTA1NDY4IDExOS4zMDg1OTQtMTcuNjI1IDE1LjAxNTYyNS0zNy41OTc2NTcgMzIuMDM5MDYyLTU4LjMyODEyNiA1MC4xNjc5NjktNS40NzI2NTYgNC43ODkwNjItMTIuNTAzOTA2IDcuNDI5Njg3LTE5Ljc4OTA2MiA3LjQyOTY4N3ptLTExMi45Njg3NS00MjUuNTIzNDM3Yy0zMS4wNjY0MDYgMC01OS42MDU0NjkgMTIuMzk4NDM3LTgwLjM2NzE4OCAzNC45MTQwNjItMjEuMDcwMzEyIDIyLjg1NTQ2OS0zMi42NzU3ODEgNTQuNDQ5MjE5LTMyLjY3NTc4MSA4OC45NjQ4NDQgMCAzNi40MTc5NjggMTMuNTM1MTU3IDY4Ljk4ODI4MSA0My44ODI4MTMgMTA1LjYwNTQ2OCAyOS4zMzIwMzEgMzUuMzk0NTMyIDcyLjk2MDkzNyA3Mi41NzQyMTkgMTIzLjQ3NjU2MiAxMTUuNjI1bC4wOTM3NS4wNzgxMjZjMTcuNjYwMTU2IDE1LjA1MDc4MSAzNy42Nzk2ODggMzIuMTEzMjgxIDU4LjUxNTYyNSA1MC4zMzIwMzEgMjAuOTYwOTM4LTE4LjI1MzkwNyA0MS4wMTE3MTktMzUuMzQzNzUgNTguNzA3MDMxLTUwLjQxNzk2OSA1MC41MTE3MTktNDMuMDUwNzgxIDk0LjEzNjcxOS04MC4yMjI2NTYgMTIzLjQ2ODc1LTExNS42MTcxODggMzAuMzQzNzUtMzYuNjE3MTg3IDQzLjg3ODkwNy02OS4xODc1IDQzLjg3ODkwNy0xMDUuNjA1NDY4IDAtMzQuNTE1NjI1LTExLjYwNTQ2OS02Ni4xMDkzNzUtMzIuNjc1NzgxLTg4Ljk2NDg0NC0yMC43NTc4MTMtMjIuNTE1NjI1LTQ5LjMwMDc4Mi0zNC45MTQwNjItODAuMzYzMjgyLTM0LjkxNDA2Mi0yMi43NTc4MTIgMC00My42NTIzNDQgNy4yMzQzNzQtNjIuMTAxNTYyIDIxLjUtMTYuNDQxNDA2IDEyLjcxODc1LTI3Ljg5NDUzMiAyOC43OTY4NzQtMzQuNjA5Mzc1IDQwLjA0Njg3NC0zLjQ1MzEyNSA1Ljc4NTE1Ny05LjUzMTI1IDkuMjM4MjgyLTE2LjI2MTcxOSA5LjIzODI4MnMtMTIuODA4NTk0LTMuNDUzMTI1LTE2LjI2MTcxOS05LjIzODI4MmMtNi43MTA5MzctMTEuMjUtMTguMTY0MDYyLTI3LjMyODEyNC0zNC42MDkzNzUtNDAuMDQ2ODc0LTE4LjQ0OTIxOC0xNC4yNjU2MjYtMzkuMzQzNzUtMjEuNS02Mi4wOTc2NTYtMjEuNXptMCAwIiBmaWxsPSIjMDAwMDAwIi8+PC9zdmc+Cg==' );
width: 1.25em;
height: 1.25em;
display: inline-block;
vertical-align: middle;
opacity: .5;
transition: transform .2s;
}
&:hover::before {
transform: scale( 1.2 );
}
&.liked::before {
background-image: url( 'data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIC0yOCA1MTIuMDAwMDEgNTEyIiB3aWR0aD0iNTEycHgiIGhlaWdodD0iNTEycHgiPjxwYXRoIGQ9Im01MTIgMTUzLjg2NzE4OGMwIDQzLjI5Mjk2OC0xNi4xMzI4MTIgODIuOTQxNDA2LTUwLjc3MzQzOCAxMjQuNzM0Mzc0LTMwLjk5NjA5MyAzNy4zOTg0MzgtNzUuNTMxMjUgNzUuMzU1NDY5LTEyNy4xMTMyODEgMTE5LjMwODU5NC0xNy42MjUgMTUuMDE1NjI1LTM3LjU5NzY1NiAzMi4wMzkwNjMtNTguMzIwMzEyIDUwLjE3MTg3NS01LjQyOTY4OCA0Ljc1LTEyLjM4NjcxOSA3LjM4NjcxOS0xOS42MTMyODEgNy40Mjk2ODhoLS4xNzk2ODhjLTcuMjg5MDYyIDAtMTQuMzE2NDA2LTIuNjQwNjI1LTE5Ljc5Mjk2OS03LjQzNzUtMjAuNjgzNTkzLTE4LjA4NTkzOC00MC42MjUtMzUuMDg5ODQ0LTU4LjIxODc1LTUwLjA4NTkzOGwtLjA4OTg0My0uMDY2NDA2Yy01MS41NzQyMTktNDMuOTU3MDMxLTk2LjEyODkwNy04MS45MjE4NzUtMTI3LjExNzE4OC0xMTkuMzIwMzEzLTM0LjY0ODQzOC00MS43OTI5NjgtNTAuNzgxMjUtODEuNDQxNDA2LTUwLjc4MTI1LTEyNC43MzQzNzQgMC00Mi4wNjY0MDcgMTQuNDI1NzgxLTgwLjg4MjgxMyA0MC42MTcxODgtMTA5LjI5Mjk2OSAyNi41MDc4MTItMjguNzUgNjIuODc1LTQ0LjU3NDIxOSAxMDIuNDE0MDYyLTQ0LjU3NDIxOSAyOS41NTg1OTQgMCA1Ni42MTcxODggOS4zMzU5MzggODAuNDQ5MjE5IDI3Ljc2MTcxOSAxMi4wMjczNDMgOS4zMDQ2ODcgMjIuOTIxODc1IDIwLjY3OTY4NyAzMi41MTk1MzEgMzMuOTY0ODQzbC4xNzk2ODgtLjIzODI4MWM5LjU1ODU5My0xMy4xODM1OTMgMjAuMzk0NTMxLTI0LjQ4MDQ2OSAzMi4zNDc2NTYtMzMuNzI2NTYyIDIzLjgyNDIxOC0xOC40MjU3ODEgNTAuODk0NTMxLTI3Ljc2MTcxOSA4MC40NDE0MDYtMjcuNzYxNzE5IDM5LjU0Njg3NSAwIDc1LjkxNDA2MiAxNS44MjQyMTkgMTAyLjQxNDA2MiA0NC41NzQyMTkgMjYuMTkxNDA3IDI4LjQxMDE1NiA0MC42MTcxODggNjcuMjE0ODQzIDQwLjYxNzE4OCAxMDkuMjkyOTY5em0wIDAiIGZpbGw9IiNmZjVlOTUiLz48cGF0aCBkPSJtNTEyIDE1My44NjcxODhjMCA0My4yOTI5NjgtMTYuMTMyODEyIDgyLjk0MTQwNi01MC43NzM0MzggMTI0LjczNDM3NC0zMC45OTYwOTMgMzcuMzk4NDM4LTc1LjUzMTI1IDc1LjM1NTQ2OS0xMjcuMTEzMjgxIDExOS4zMDg1OTQtMTcuNjI1IDE1LjAxNTYyNS0zNy41OTc2NTYgMzIuMDM5MDYzLTU4LjMyMDMxMiA1MC4xNzE4NzUtNS40Mjk2ODggNC43NS0xMi4zODY3MTkgNy4zODY3MTktMTkuNjEzMjgxIDcuNDI5Njg4di0zOTQuMDIzNDM4YzkuNTU4NTkzLTEzLjE4MzU5MyAyMC4zOTQ1MzEtMjQuNDgwNDY5IDMyLjM0NzY1Ni0zMy43MjY1NjIgMjMuODI0MjE4LTE4LjQyNTc4MSA1MC44OTQ1MzEtMjcuNzYxNzE5IDgwLjQ0MTQwNi0yNy43NjE3MTkgMzkuNTQ2ODc1IDAgNzUuOTE0MDYyIDE1LjgyNDIxOSAxMDIuNDE0MDYyIDQ0LjU3NDIxOSAyNi4xOTE0MDcgMjguNDEwMTU2IDQwLjYxNzE4OCA2Ny4yMTQ4NDMgNDAuNjE3MTg4IDEwOS4yOTI5Njl6bTAgMCIgZmlsbD0iI2ZmMzk4MCIvPjwvc3ZnPgo=' );
opacity: 1;
}
&::after {
content: attr( data-liked-count );
margin-left: .25em;
color: #000;
}
&.loading::after {
content: '';
width: 1em;
height: 1em;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
max-width: 512px;
max-height: 512px;
width: 1em;
height: 1em;
display: inline-block;
vertical-align: middle;
transform-origin: center center;
animation-name: like-loading;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-fill-mode: backwards;
background-image: url( 'data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4IiB2aWV3Qm94PSIwIDAgMzQ0LjM3IDM0NC4zNyIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzQ0LjM3IDM0NC4zNzsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxnPgoJCTxwYXRoIGQ9Ik0zMzQuNDg1LDM3LjQ2M2MtNi43NTMtMS40NDktMTMuMzk2LDIuODUzLTE0Ljg0Miw5LjYwM2wtOS4wODQsNDIuMzkxQzI4MS42MzcsNDAuMTE3LDIyOC41NTEsOS4xNTUsMTcwLjM2OCw5LjE1NSAgICBjLTg5LjYwMywwLTE2Mi41LDcyLjg5Ni0xNjIuNSwxNjIuNWMwLDYuOTAzLDUuNTk2LDEyLjUsMTIuNSwxMi41YzYuOTAzLDAsMTIuNS01LjU5NywxMi41LTEyLjUgICAgYzAtNzUuODE4LDYxLjY4Mi0xMzcuNSwxMzcuNS0xMzcuNWM0OS40MjksMCw5NC41MTUsMjYuNDAzLDExOC45MjUsNjguNDQzbC00MS42NzQtOC45MzFjLTYuNzUyLTEuNDQ3LTEzLjM5NiwyLjg1NC0xNC44NDEsOS42MDQgICAgYy0xLjQ0Niw2Ljc1LDIuODU0LDEzLjM5Niw5LjYwNCwxNC44NDJsNzEuNTM2LDE1LjMzYzEuMjE1LDAuMjYxLDIuNDQ5LDAuMzM2LDMuNjY2LDAuMjM0YzIuMDI3LTAuMTcxLDQuMDAzLTAuODM2LDUuNzQzLTEuOTYyICAgIGMyLjc4NC0xLjgwMSw0LjczOC00LjYzNCw1LjQzMy03Ljg3NWwxNS4zMzEtNzEuNTM2QzM0NS41MzUsNDUuNTU1LDM0MS4yMzUsMzguOTExLDMzNC40ODUsMzcuNDYzeiIgZmlsbD0iIzAwMDAwMCIvPgoJCTxwYXRoIGQ9Ik0zMjEuOTA3LDE1NS4yNzFjLTYuODk5LDAuMjI4LTEyLjMwOSw2LjAwNi0xMi4wODEsMTIuOTA1YzEuMjEyLDM2LjcwOC0xMS45NDIsNzEuNjg5LTM3LjA0Miw5OC41MDQgICAgYy0yNS4wOTksMjYuODEyLTU5LjEzNyw0Mi4yNDgtOTUuODQ0LDQzLjQ2Yy0xLjUzLDAuMDUtMy4wNTIsMC4wNzUtNC41NzYsMC4wNzVjLTQ3Ljg5Ni0wLjAwMi05Mi4wMTgtMjQuODc3LTExNi45MzYtNjUuMTggICAgbDQzLjQ0NywxMS42NWM2LjY2OCwxLjc4NywxMy41MjMtMi4xNjgsMTUuMzExLTguODM3YzEuNzg4LTYuNjY4LTIuMTY4LTEzLjUyMi04LjgzNi0xNS4zMTJsLTcwLjY2NC0xOC45NDYgICAgYy0zLjIwMi0wLjg1Ny02LjYxNS0wLjQwOS05LjQ4NSwxLjI0N2MtMi44NzIsMS42NTYtNC45NjcsNC4zODctNS44MjYsNy41ODlMMC40MywyOTMuMDkyICAgIGMtMS43ODgsNi42NjgsMi4xNjgsMTMuNTIyLDguODM2LDE1LjMxMWMxLjA4NSwwLjI5MSwyLjE3MywwLjQzMSwzLjI0NSwwLjQzMWM1LjUxOCwwLDEwLjU2OS0zLjY4NCwxMi4wNjYtOS4yNjdsMTAuNjQ5LTM5LjcxNyAgICBjMjkuNjI0LDQ2LjY0Nyw4MS4xODksNzUuMzY3LDEzNy4xMzIsNzUuMzY1YzEuNzk3LDAsMy42MDQtMC4wMjksNS40MDgtMC4wODljNDMuMzgxLTEuNDM0LDgzLjYwOC0xOS42NzQsMTEzLjI3MS01MS4zNjIgICAgczQ1LjIwOS03My4wMzEsNDMuNzc2LTExNi40MTNDMzM0LjU4NiwxNjAuNDUzLDMyOC44MDUsMTU1LjAyNiwzMjEuOTA3LDE1NS4yNzF6IiBmaWxsPSIjMDAwMDAwIi8+Cgk8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==' );
}
}
Висновок
Цей метод дуже простий, але не позбавлений недоліків пов’язаних з можливістю накрутки, при бажанні це можна виправити і вдосконалити його. А саме:
- додати віджет або шорткод з вибіркою популярних потів;
- поліпшити захист від накрутки;
- для ідентифікації користувачів використовувати скрипт google-аналітики;
- на основі масиву ідентифікаторів вподобаних постів сформувати список обраного
Під час розробки WordPress-теми таку кнопку легко додати як «дефолтну», а згодом і при необхідності замінити на більш просунутий функціонал. Варіантів безліч.
Git-проект: https://github.com/chomovva/wp-simple-likes