На самом деле мы будем производить подсчет не "скачиваний" а кликов по нужным ссылкам, т.е. если в посте кликнули по ссылке "скачать" - считаем что файл скачан, не важно что там дальше сделает пользователь.
1. Создаем новую таблицу в базе
Итак, начнем мы с создания новой таблицы, в которой будем хранить данные о скачиваниях для каждого поста за сутки.
Назовем таблицу: wp_day_download
Сделаем столбцы: post_id | date | dl
2. Создаем файл редиректа
Теперь в корне нашего сайта надо создать новый php файл, который будет использоваться для редиректа нужных ссылок. Через него то и будут считаться скачивания (заноситься в базу)
Доп. бонус редиректа в том, что мы можем поставить на нем задержку, например в 10 сек, и показать там рекламу и через 10 сек перенаправить пользователя по ссылке.
Назовем файл dl.php и добавим в него следующий код:
<?php
// Смотрим есть ли что то в url
$url=isset($_REQUEST['url']) ? $_REQUEST['url'] : '';
// Если есть декодируем
$url = urldecode($url);
//Смотрим есть ли что то в id
$post_id = (int) isset($_REQUEST['id']) ? $_REQUEST['id'] : '';
// Проверяем что id поста - число и оно больше 0
if(is_numeric($post_id) AND $post_id > 0){
// указываем, что нам нужен минимум от WP
define('SHORTINIT', true);
// подгружаем среду WordPress
// WP делает некоторые проверки и подгружает только самое необходимое для подключения к БД
require_once( $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php' );
// тут мы можем общаться с БД. Но практически никакие функции WP работать не будут.
// Глобальные переменные $wp, $wp_query, $wp_the_query не установлены...
global $wpdb;
// Проверяем есть ли пост с переданным id
$pst = $wpdb->query ( "SELECT * FROM wp_posts WHERE ID = $post_id AND post_type = 'post' LIMIT 1" );
// Если пост с нашим id есть в базе
if ($pst == 1) {
// берем -- meta_id с meta_key downloads -- нашего поста
$row =(int) $wpdb->get_var( "SELECT meta_id FROM wp_postmeta WHERE post_id=$post_id AND meta_key='downloads' LIMIT 1" );
// сегодня в формате 2016-02-29 (+3 часа для МСК)
$date = date('Y-m-d', strtotime("+3 hours"));
// Заносим суммарные скачивания поста в мета-данные этого поста
$wpdb->query("INSERT INTO wp_postmeta SET meta_id = $row, post_id = $post_id,meta_key = 'downloads',meta_value = 1 ON DUPLICATE KEY UPDATE meta_value=meta_value + 1");
// Заносим в нашу созданную таблицу суточные скачивания поста
$wpdb->query("INSERT INTO wp_day_download SET post_id = $post_id, date = '$date', dl = 1 ON DUPLICATE KEY UPDATE dl=dl + 1");
// Перенаправляем пользователя по ссылке с задержкой 0 сек
header("Refresh:0; URL=".$url."");
//Так же тут можно вывести какой-то HTML код и изменить задержку перенаправления
// что позволит показать рекламку или вывести кнопку --перейти--
// Если поста с нашим id в базе нет, показываем ошибку
} else {
exit ("Ошибка. Хакер что ли?2");
// Если ид поста не число или оно равно или меньше 0 то редиректим на страницу 404
} else {
header("Location: /page/404.html");
exit;
}
?>
Как вы заметили мы будем использовать define('SHORTINIT', true); а это значит что почти никакие функции wordpress в этом файле работать не будут, но тут этого и не нужно. А нагрузки нет никакой!
Ну что же, теперь думаю понятно что ссылки на скачивание у нас будут иметь вид:
site.ru/dl.php?url=<закодированный url>&id=<ид поста>
3. Конвертируем ссылки в постах в нужный формат
Теперь нам осталось только конвертировать ссылки в нужный формат.
Т.к. у меня на сайте больше 10.000 записей - отредактировать все ссылки ручками это очень тяжело, тогда решено было написать функцию которая будет фильтровать контент поста и заменять ссылки на НУЖНЫЕ домены.
Да-да, мы будем заменять ссылки только на те домены, где лежит файл. Конечно если писать сайт с нуля, я бы сделал для ссылок какое-то мета-поле и заменял бы только ссылки из него, но и в нашем случае все будет работать отлично.
В functions.php необходимо добавить следующий код
function filter_function_name_11( $content ) {
global $post;
$posttype = get_post_type($post->ID);
// Работаем только с постами типа post
if ($posttype == 'post') {
// Массив с доменами ссылки на которые НАДО заменить
$blacklists = array ('fileplanet.', 'yadi.sk' );
// Берем содержимое HREF всех ссылок постов и записываем в $links
preg_match_all('~<a.*?href="([^"]+)".*?>(.*?)</a>~s', $content, $links);
// Просматриваем каждую ссылку отдельно
foreach ($links[1] as $l) {
// Берем по 1ой ссылку из массива с теми доменами, на которые надо заменять ссылки
foreach ($blacklists as $blacklist) {
// Если в Nой ссылке есть домент из черного списка - заменяем
if (strpos($l,$blacklist)) {
$content = str_replace('href="'.$l,'href="/dl.php?url='.urlencode($l).'&id='.$post->ID.'" class="dl-link" target="_blank" rel="nofollow', $content);
}
}
}
}
return $content;
}
add_filter( 'the_content', 'filter_function_name_11' );
Тут конечно 99% что не самый "Оптимальный" способ проверки, но вроде никакой особой нагрузки нет. В любом случае буду рад любым замечаниям - с радостью внесу их и у себя на сайте, а не только тут.
Так же, как вы могли заменить, нужным ссылкам мы присвоим class="dl-link" - можно использовать его для выделения таких ссылок.
4. Важно. Код для single.php
Как вы поняли общие скачивания мы будем заносить в мета поле поста, однако его немного геморно создавать в файле dl.php, но выход очень прост:
В single.php добавьте (в цикле конечно же):
$downloads = get_post_meta($post->ID, "downloads", true);
if (!$downloads) { add_post_meta($post->ID, 'downloads', '0', true); }
И все будет отлично: после того как кто-то откроет пост - проверится есть ли у него мета поле downloads и если нет - добавится. А значит клик по нашей сгенерированной ссылке внутри поста нормально отработается.
Ну и итог:
Как показать общие скачивания?
get_post_meta($post->ID, "downloads", true);
Как показать скачивания за сутки?
global $wpdb;
$date = date('Y-m-d', strtotime("+3 hours"));
$post_id = $post->ID;
$dlToDay = $wpdb->get_var("SELECT dl FROM wp_day_download WHERE post_id=$post_id AND date='$date'");
echo $dlToDay;
Как показать скачивания за N дней?
global $wpdb;
$day = 7; // Кол-во дней за которые показать скачивания
$post_id = $post->ID;
$dlByDay = $wpdb->get_var("SELECT SUM(dl) FROM wp_day_download WHERE post_id=$post_id AND date>=DATE_ADD(CURRENT_TIMESTAMP,INTERVAL -".$day." DAY)");
echo $dlByDay;



Еще я знаю как в категории вывести записи отсортированные по скачиваниям за N дней и с пагинацией! 🙂
А так же я немного видоизменил плагин подсчета просмотров от wp-kama и теперь он считает суточные просмотры каждого поста (по аналогии этого поста) А так же на основе кода выше я могу выводить записи по просмотрам за сегодня, вчера, неделю и т.п.
Если кому то надо - и это все опишу
Спасибо, действительно полезная статья.
Все же было бы идеально избавится от необходимости внедрения кода в single.php и все делать в dl.php.
Да и в прямых запросах к БД иногда может быть критичным указание префикса через $wpdb->prefix, тк не у всех он 'wp_'
Да, но табличку мы тут ручками создаем, так что не думаю что в данном случае кто-то упустит момент с префиксом.
Мета поле из single можно перенести и в dl.php (создавать прямым запросом к бд) и в functions.php - создавать только тем постам, в которых заменяем, куда "лучше" - я хз. Однако мы же в любом случае в single.php будем получать значения мета поля и отображать его (по крайней мере у меня так)
И да, создание таблички то же можно перенести в dl.php и каждый раз проверять есть ли она (нет ли от этого нагрузки?) Но там надо не просто создать табличку, а еще создать индекс по post_id и data (если я правильно все понимаю то это действительно нужно). А как запросом это все сделать я пока не знаю.
-----------------------
Но я посмотрю и попробую больше автоматизировать и сделать меньше вставок.
Интересное решение и конечно полегче чем аналогичные плагины(тут я не очень силен). Но достаточно персонализированное. Было бы просто чудесно, если вы сможете собрать плагин, без вставок ручных и тд, с выводом статы например в админке или не важно где и как... Тогда тут же взяли бы в работу сие. Сейчас используется плагин от всем или многим известного Tkama(wp-kama), но он грузноват для проектов где не нужно отслеживать сотни ссылок.
Да нет, у него как раз все норм написано. Не думаю что там так же есть какая-то нагрузка, ибо все ссылки - шорткоды, или вообще ищутся по классу с помощью jquery. Так что если он вас устраивает - не стоит переживать о какой-то нагрузке.
А какая вам стата нужна я не понял, в этом посте, если что, нельзя отследить скачивания определенных файлов (только если 1 пост 1 файл), все клики по ссылкам в посте учитываются как единое целое.
Спасибо за разъяснение.
насчет статы все ок, я немного не так просто написал.
Приветствую. Вопрос к автору: а как все это дело будет с кешированием работать? Или если скажем исключить страницу dl.php из кеширования, то все нормально будет считаться?
dl.php лежит в корне сайта и никакие плагины wordpress его кешировать не должны, я никаких проблем с этим не заметил