статья обновлена февраль 2021г. (внесены изменения, с учетом накопленных знаний)
В процессе создания и эксплуатации плагина WatchMan-Site7 мне пришла в голову идея создать такой механизм, который мог бы сам, без ручного вмешательства со стороны админа – обновлял основной экран посещений всех типов посетителей (людей, роботов) по мере их появления на сайте. Потому что – надоело: сидишь в админке и как дятел стучишь по клавише “обновить” экран браузера, что бы увидеть новых посетителей сайта. Пусть бы сам сайт посылал мне в браузер информацию о новых посещениях по мере их поступления!
Пришлось углубиться в теорию. И вот, что я накопал… Существуют три технологии динамической связи “клиент-сервер”:
1. AJAX (набор ранее существующих технологий – JS, PHP, HTML)
2. WebSocket (мощная вещь, но достаточно сложная в реализации)
3. SSE (Server-Sent Events)
Пришлось познакомиться с перечисленными технологиями, причем зная, что базовый класс WP_LIST_TABLE в WordPress адаптирован к технологии AJAX. И поэтому, подспудно, думая на какой технологии остановиться, я склонялся к AJAX. Однако, спустя некоторое время, я все-таки остановился на технологии SSE ( спецификация SSE ). И вот, как это удалось реализовать.
На стороне сервера:
(строка 6) – подключается файл wms7-sse-backend.php в котором находится функционал по сбору и передаче одних данных на сторону клиента.
(строка 7) – активируется функция “wms7_sse_backend” при срабатывании хука “wp_ajax_backend” для того, кто залогинился.
(строка 11) – подключается файл wms7-sse-frontend.php в котором находится функционал по сбору и передаче других данных на сторону клиента.
(строка 12) – активируется функция “wms7_sse_frontend” при срабатывании хука “wp_ajax_frontend” для того, кто залогинился.
(строка 13) – активируется та же функция “wms7_sse_frontend” при срабатывании хука “wp_ajax_nopriv_frontend” для того, кто не залогинился.
<?php ... /** * Used to send a count of records of visitor, number of unseen emails. */ require_once __DIR__ . "/includes/wms7-sse-backend.php"; add_action( "wp_ajax_backend", "wms7_sse_backend" ); /** * Used to transfer data about site visits to a widget - counter of visits. */ require_once __DIR__ . "/includes/wms7-sse-frontend.php"; add_action( "wp_ajax_frontend", "wms7_sse_frontend" ); add_action( "wp_ajax_nopriv_frontend", "wms7_sse_frontend" ); ...Теперь посмотрим на код в файле “/includes/wms7-sse-backend.php”, который был подключен выше. Тут находим в строке 40 функцию “wms7_sse_backend”, указанную выше в строке 7 основного файла плагина watchman-site7.php
<?php
/**
* Description: Used to send a count of records of visitor, number of unseen emails.
*
* PHP version 7.4
*
* @category Wms7-sse-backend.php
* @package WatchMan-Site7
* @author Oleg Klenitskiy <klenitskiy.oleg@mail.ru>
* @version 4.0.0
* @license GPLv2 or later
*/
/**
* Used for Serves to send information to the client browser (backend of site).
*
* @param string $data Number of visits records and mails inbox unseen.
*/
function wms7_send_backend( $data ) {
if ( ! headers_sent() ) {
header( 'Content-Type: text/event-stream' );
header( 'Cache-Control: no-cache' );
header( 'Connection: keep-alive' );
header( 'Access-Control-Expose-Headers: *' );
echo 'data: ' . json_encode( $data );
echo ';' . json_encode( current_time( 'mysql' ) );
echo "\n\n";
}
// check for output_buffering activation.
if ( 0 !== count( ob_get_status() ) ) {
ob_flush();
}
flush();
}
/**
* Used for Serves to send information to the client browser (backend of site).
*/
function wms7_sse_backend() {
$_wms7_nonce = filter_input( INPUT_GET, 'wms7_nonce', FILTER_SANITIZE_STRING );
if ( !isset($_wms7_nonce) ) {
wp_die( 'wms7_nonce: nonce is empty.' );
}
if ( $_wms7_nonce !== wp_create_nonce( 'wms7_nonce' ) ) {
wp_die( 'wms7_nonce: nonce is incorrect.' );
}
wms7_send_backend( get_option('backend', '0,0') );
wp_die();
}
/**
* Used for to obtain the number of visits records.
*
* @return number.
*/
function wms7_count_rows() {
global $wpdb;
$results = $wpdb->get_var(
$wpdb->prepare(
"
SELECT count(%s) FROM {$wpdb->prefix}watchman_site
",
'*'
)
);// db call ok; no cache ok.
return $results;
}
На стороне клиента:
/**
* Description: Used to manage the plug-in on the client side.
*
* @category Wms7_backend.js
* @package WatchMan-Site7
* @author Oleg Klenitskiy <klenitskiy.oleg@mail.ru>
* @version 4.0.0
* @license GPLv2 or later
*/
/**
* Process Control Server Sent Events on the client side (backend).
*/
function wms7_sse_backend() {
let sse = document.getElementById( "sse" );
if (sse.checked) {
wms7_ctrl_sound("sse_on");
// start SSE backend.
localStorage.setItem("wms7_sse_backend", "on" );
if ( window.EventSource ) {
let wms7_source = new EventSource( wms7_ajax_url + "?action=backend" + "&wms7_nonce=" + wms7_nonce);
wms7_source.onmessage = function(e) {
let arr = e.data.replace(/"/g, '').split( ";" );
let arr_add = arr[0].split( "," );
console.log( "All visits=" + arr_add[0] + " New letters=" + arr_add[1] + " Server time=" + arr[1] + " Origin=" + e.origin );
if (localStorage.getItem( "wms7_records_count" ) !== arr_add[0] || localStorage.getItem( "wms7_unseen_count" ) !== arr_add[1] ) {
localStorage.setItem("wms7_records_count", arr_add[0] );
localStorage.setItem("wms7_unseen_count", arr_add[1] );
wms7_beep();
location.replace( window.location.href );
}
}
} else {
alert( "Your browser does not support Server-Sent Events. Execution stopped." );
return;
}
} else {
wms7_ctrl_sound("sse_off")
// stop SSE backend.
localStorage.setItem("wms7_sse_backend", "off" );
location.replace( window.location.href );
}
wms7_ctrl_btn_href();
}
Прокомментирую:
В JS коде, в строке 23 создается событие EventSource с названием action=backend, которое совпадает с название хука “wp_ajax_backend” в основном файле плагина watchman-site7.php в строке 7. Кроме этого, wms7_ajax_url = “https://you-site/wp-admin/admin-ajax.php”;
В JS коде, в строке 28 происходит сравнение ранее сохраненных данных в localStorage.getItem( “wms7_records_count” ) с вновь пришедшими данными и сохраняются в localStorage.setItem(“wms7_records_count”, arr_add[0] ) для последующего сравнения (когда придут с сервера новые данные). Затем, в строке 33 – звуковой сигнал, и в строке 34 – обновление экрана. Все действие можно наблюдать в консоли, нажав F12.
😉Совет:
Такой подход мог бы быть полезен при проведении каких-либо коммерческих акций, опросов, политических компаний, голосования…
