На самом деле мы будем производить подсчет не "скачиваний" а кликов по нужным ссылкам, т.е. если в посте кликнули по ссылке "скачать" - считаем что файл скачан, не важно что там дальше сделает пользователь.
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 его кешировать не должны, я никаких проблем с этим не заметил