Фильтрация и проверка данных PHP. Частые ошибки

Материал предназначен в основном для начинающих веб-программистов.

Введение.
Часто ко мне обращаются клиенты, у которых установлены самописные CMS или модули, написанные начинающими веб-программистами, которые не понимают, что нужно для защиты данных и зачастую копируют функции фильтрации, не задумываясь о том как они работают и что именно нужно с ними делать.

Здесь я постараюсь описать как можно подробнее частые ошибки при фильтрации данных в PHP скрипте и дать простые советы как правильно выполнить фильтрацию данных.

В сети много статей по поводу фильтрации данных, но они как правильно не полные и без подробные примеров.

Разбор полетов.

Фильтрация. Ошибка №1

Для числовых переменных используется такая проверка:

$number = $_GET['input_number'];
if (intval($number))
{
... выполняем SQL запрос ...
}


Почему она приведет к SQL инъекции? Дело в том, что пользователь может указать в переменной input_number значение:
1'+UNION+SELECT


В таком случаи проверка будет успешно пройдена, т.к. функция intval получает целочисленное значение переменной, т.е. 1, но в самой переменной $number ничего не изменилось, поэтому весь вредоносный код будет передан в SQL запрос.
Правильная фильтрация:
$number = intval($_GET['input_number']);
if ($number)
{
... выполняем SQL запрос ...
}


Конечно, условие может меняться, например если вам нужно получить только определенный диапазон:
if ($number >= 32 AND $number <= 65)



Если вы используете чекбоксы или мультиселекты с числовыми значениями, выполните такую проверку:
$checkbox_arr = array_map('intval', $_POST['checkbox']);


array_map
Так же встречаю фильтрацию в виде:
$number = htmlspecialchars(intval($_GET['input_number']));

htmlspecialchars
Или:
$number = mysql_escape_string(intval($_GET['input_number']));


mysql_escape_string

Ничего кроме улыбки это не может вызвать :)

Фильтрация. Ошибка №2.

Для стринг-переменных используется такая фильтрация:
$input_text = addslashes($_GET['input_text']);


Функция addslashes экранирует спец. символы, но она не учитывает кодировку БД и возможен обход фильтрации. Не стану копировать текст автора, который описал данную уязвимость и дам просто ссылку Chris Shiflett (перевод можно поискать в рунете).

Используйте функцию mysql_escape_string или mysql_real_escape_string, пример:
$input_text = mysql_escape_string($_GET['input_text']);


Если вы не предполагаете вхождение html тегов, то лучше всего сделать такую фильтрацию:
$input_text = strip_tags($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text);

strip_tags — убирает html теги.
htmlspecialchars — преобразует спец. символы в html сущности.
Так вы защитите себя от XSS атаки, помимо SQL инъекции.
Если же вам нужны html теги, но только как для вывода исходного кода, то достаточно использовать:
$input_text = htmlspecialchars($_GET['input_text']);
$input_text = mysql_escape_string($input_text);



Если вам важно, чтобы значение переменной не было пустой, то используйте функцию trim, пример:
$input_text = trim($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text);



Фильтрация. Ошибка №3.

Она касается поиска в БД.
Для поиска по числам используйте фильтрацию, описанную в первой ошибке.
Для поиска по тексту используйте фильтрацию, описанную во второй ошибке, но с оговорками.
Для того, чтобы пользователь не смог выполнить логическую ошибку, нужно удалять или экранировать спец. символы SQL.
Пример без доп. обработки строки:
$input_text = htmlspecialchars($_GET['input_text']); // Поиск: "%"
$input_text = mysql_escape_string($input_text);


На выходе у нас получится запрос вида:
... WHERE text_row LIKE '%".$input_text."%' ... // WHERE text_row LIKE '%%%'


Это значительно увеличит нагрузку на базу.
В своём скрипте я использую функцию, которая удаляет нежелательные мне символы из поиска:
function strip_data($text)
{
    $quotes = array ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!" );
    $goodquotes = array ("-", "+", "#" );
    $repquotes = array ("\-", "\+", "\#" );
    $text = trim( strip_tags( $text ) );
    $text = str_replace( $quotes, '', $text );
    $text = str_replace( $goodquotes, $repquotes, $text );
    $text = ereg_replace(" +", " ", $text);
            
    return $text;
}


Конечно, не все из выше перечисленных символов представляют опасность, но в моём случаи они не нужны, поэтому выполняю поиск и замену.
Пример использования фильтрации:
$input_text = strip_data($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text);


Также советую сделать ограничение по количеству символов в поиске, хотя бы не меньше 3-х, т.к. если у вас будет большое количество записей в базе, то поиск по 1-2 символам будет значительно увеличивать нагрузку на БД.

Фильтрация. Ошибка №4.

Не фильтруются значения в переменной $_COOKIE. Некоторые думаю, что раз эту переменную нельзя передать через форму, то это гарантия безопасности.
Данную переменную очень легко подделать любым браузером, отредактировав куки сайта.
Например, в одной известной CMS была проверка, используемого шаблона сайта:
if (@is_dir ( MAIN_DIR . '/template/' . $_COOKIE['skin'] )){
	$config['skin'] = $_COOKIE['skin'];
}
$tpl->dir = MAIN_DIR . '/template/' . $config['skin'];


В данном случаи можно подменить значение переменной $_COOKIE['skin'] и вызвать ошибку, в результате которой вы увидите абсолютный путь до папки сайта.
Если вы используете значение куков для сохранения в базу, то используйте одну из выше описанных фильтраций, тоже касается и переменной $_SERVER.

Фильтрация. Ошибка №5.

Включена директива register_globals. Обязательно выключите её, если она включена.
В некоторых ситуациях можно передать значение переменной, которая не должна была передаваться, например, если на сайте есть группы, то группе 2 переменная $group должна быть пустой или равняться 0, но достаточно подделать форму, добавив код:
<input type="text" name="group" value="5" />


В PHP скрипте переменная $group будет равна 5, если в скрипте она не была объявлена со значением по умолчанию.

Фильтрация. Ошибка №6.

Проверяйте загружаемые файлы.
Выполняйте проверку по следующим пунктам:
1. Расширение файла. Желательно запретить загрузку файлов с расширениями: php, php3, php4, php5 и т.п.
2. Загружен ли файл на сервер move_uploaded_file
3. Размер файла

Проверка. Ошибка №1.

Сталкивался со случаями, когда для AJAX запроса (например: повышение репутации) передавалось имя пользователя или его ID (кому повышается репутация), но в самом PHP не было проверки на существование такого пользователя.
Например:
$user_id = intval($_REQUEST['user_id']);
... INSERT INTO REPLOG SET uid = '{$user_id}', plus = '1' ...
... UPDATE Users SET reputation = reputation+1 WHERE user_id = '{$user_id}' ...


Получается мы создаем запись в базе, которая совершенно бесполезна нам.

Проверка. Ошибка №2.

При выполнении различного рода действий (добавление, редактирование, удаление) с данными не забывайте проверять права пользователя на доступ к данной функции и дополнительные возможности (использование html тегов или возможность опубликовать материал без проверки).

Давно исправлял в одном модуле форума подобную ошибку, когда любой пользователь мог отредактировать сообщение администрации.

Проверка. Ошибка №3.

При использовании нескольких php файлов сделайте простую проверку.
В файле index.php (или в любом другом главном файле) напишите такую строчку перед подключением других php файлов:
define ( 'READFILE', true );


В начале других php файлов напишите:
if (! defined ( 'READFILE' ))
{
	exit ( "Error, wrong way to file.<br><a href=\"/\">Go to main</a>." );
}


Так вы ограничите доступ к файлам.

Проверка. Ошибка №4.

Используйте хеши для пользователей. Это поможет предотвратить вызов той или иной функции путём XSS.
Пример составления хеша для пользователей:
$secret_key = md5( strtolower( "http://site.ru/" . $member['name'] . sha1($password) . date( "Ymd" ) ) ); // $secret_key - это наш хеш


Далее во все важные формы подставляйте инпут со значением текущего хеша пользователя:
<input type="hidden" name="secret_key" value="$secret_key" />


Во время выполнения скрипта осуществляйте проверку:
if ($_POST['secret_key'] !== $secret_key)
{
exit ('Error: secret_key!');
}



Проверка. Ошибка №5.

При выводе SQL ошибок сделайте простое ограничение к доступу информации. Например задайте пароль для GET переменной:
if ($_GET['passsql'] == "password")
{
... вывод SQL ошибки ...
}
else
{
... Просто информация об ошибке, без подробностей ...
}


Это позволит скрыть от хакера информацию, которая может ему помочь во взломе сайта.

Проверка. Ошибка №5.
Старайтесь не подключать файлы, получая имена файлов извне.
Например:
if (isset($_GET['file_name']))
{
include $_GET['file_name'] .'.php';
}


Используйте переключатель switch:
switch($_GET['file_name'])
{         
         case 'file_1':
         include 'file_1.php';    
         break;     
         
         default:
         include 'file_0.php';    
         break;
}


В таком случаи вы предотвратите подключение файлов, которые не были вами предусмотрены.

Совет.

Для большей надежности используйте один из готовых и популярных классов для фильтрации данных, дабы самому не пропустить какие-то вредоносные символы/данные. Также в этих классах часто имеется возможность выбора фильтра данных.

UPD: Поправил пост. Перенес все советы по поводу функций и переменных, которые были в комментариях.

Добавлено: 19 Ноября 2021 07:27:05 Добавил: Андрей Ковальчук

Как в mysql лучше всего хранить ip адрес?

Наиболее удобно ip-адрес в MySQL хранить в типе INT. Причём обязательно UNSIGNED (беззнаковый), чтобы адреса выше 127. вполне вмещались в эти 4 байта.

`ip` int(10) unsigned NOT NULL

Тип INT более удобен для хранения ip-адресов по сравнению с CHAR(15) по двум причинам:

Требует меньше памяти (4 байта INT против 15 байт CHAR). Как результат, таблица занимает меньше места на диске, а скорость выполнения запросов возрастает, т.к. индекс меньшего размера.
Удобно производить выборки по диапазонам адресов и маскам, а также делать сортировку (получается обычная сортировка по числам).
Имеется недостаток по сравнению с хранением ip как plaintxt (char или varchar) в mysql:

Необходимость дополнительного преобразования ip-строки в число и наоборот для удобства восприятия. Для чего используются функции INET_ATON и INET_NTOA (см. дальше). Но это ведь не проблема.
Как видно, достоинства хранения ip в UNSIGNED INT сильно превосходят единственный недостаток.

Функции преобразования ip-адреса в mysql:

INET_ATON() — для преобразования IP адреса в число,
INET_NTOA() — для обратного преобразования числа в IP адрес.

Для простоты запоминания нужно знать расшифровку аббревиатуры:

ATON — Address TO Number (адрес в число),
NTOA — Number TO Address (число в адрес).

Примеры преобразования IP в mysql:
SELECT INET_NTOA(ip) FROM tablename LIMIT 10;  # выведет ip в обычном строковом формате
 
SELECT INET_ATON('127.0.0.1');    #2130706433
SELECT INET_ATON('93.125.99.10');  #1568498442
 
SELECT INET_NTOA(2130706433);   #127.0.0.1
SELECT INET_NTOA(1568498442);   #93.125.99.10

Аналогичные функции преобразования ip-адреса в PHP:

ip2long() — для преобразования IP адреса в число;
long2ip() — для обратного преобразования числа в IP адрес.
ip2long('127.0.0');     //false
ip2long('93.125.99.10'); //1568498442
ip2long('127.0.0.1');    //2130706433
ip2long('192.168.0.1'); //3232235521

long2ip('1568498442'); //93.125.99.10
long2ip('2130706433'); //127.0.0.1
long2ip('3232235521'); //192.168.0.1

Задача. Нам нужно получить все записи, которые находятся в диапазоне адресов 148.100.0.0 — 158.255.255.255. Если хранить IP в виде строк, то пришлось бы производить поиск с помощью регулярных выражений, а запрос выполнялся бы очень долго.

В случае хранения IP-адреса в типе INT sql-запрос будет таким:
SELECT .... WHERE ip BETWEEN INET_ATON('148.100.0.0') AND INET_ATON('158.255.255.255')

Добавлено: 14 Ноября 2021 07:17:57 Добавил: Андрей Ковальчук

Поиск пустых папок. Идеи и реализации

function RemoveEmptySubFolders($path)
{
  $empty=true;
  foreach (glob($path.DIRECTORY_SEPARATOR."*") as $file)
  {
     if (is_dir($file))
     {
        if (!RemoveEmptySubFolders($file)) $empty=false;
     }
     else
     {
        $empty=false;
     }
  }
  if ($empty) rmdir($path);
  return $empty;
}

Добавлено: 21 Октября 2021 06:55:44 Добавил: Андрей Ковальчук

Как отключить прилепленные записи на главной странице WordPress

Если у вам не нужны прикрепленные записи и у вас их= несколько, то зайдите в консоль и там просто открепите эти записи и все. Но если, на вашем сайте раньше специально прилеплялись записи, таким образом выводились избранные статьи, а теперь вы решили поменять концепцию и желания редактировать все прилепленные статьи у вас нет, то вам поможет следующая небольшая функция.

add_action( 'pre_get_posts', 'turn_off_sticky' );
function turn_off_sticky( $query ) {
    if ( $query->is_main_query() ) {
        $query->set( 'ignore_sticky_posts', true );
    }
}

Функция добавляется в файл пользовательских функций - function.php. Если не знакомы с его структурой, то добавляете в самый конец перед закрывающим тегом PHP ?>. Если его нет, то просто в самый конец файла.

Перед изменением function.php, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.


После добавления можете оценить результат.

Добавлено: 28 Сентября 2021 06:43:39 Добавил: Андрей Ковальчук

Как отключить прилепленные записи на главной странице WordPress

Если у вам не нужны прикрепленные записи и у вас их= несколько, то зайдите в консоль и там просто открепите эти записи и все. Но если, на вашем сайте раньше специально прилеплялись записи, таким образом выводились избранные статьи, а теперь вы решили поменять концепцию и желания редактировать все прилепленные статьи у вас нет, то вам поможет следующая небольшая функция.

add_action( 'pre_get_posts', 'turn_off_sticky' );
function turn_off_sticky( $query ) {
    if ( $query->is_main_query() ) {
        $query->set( 'ignore_sticky_posts', true );
    }
}

Функция добавляется в файл пользовательских функций - function.php. Если не знакомы с его структурой, то добавляете в самый конец перед закрывающим тегом PHP ?>. Если его нет, то просто в самый конец файла.

Перед изменением function.php, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.


После добавления можете оценить результат.

На этом все, спасибо за внимание.

Добавлено: 10 Сентября 2021 14:20:19 Добавил: Андрей Ковальчук

Как добавить рейтинг записей к комментариям WordPress

Я предлагаю добавить код функций будущего рейтинга прямо в файл функций function.php. Вы, если хорошо знакомы с WordPress, можете сделать плагин - Как создать плагин для WordPress, или вынести функции в отдельный файл, а потом его уже подключить в function.php, если вам так удобнее.

Добавить надо следующий код нужно в самый конец перед закрывающим тегом PHP ?>. Если его нет, то просто в самый конец.

Перед изменением function.php, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.

//ДОБАВЛЯЕМ РЕЙТИНГ К КОММЕНТАРИЯМ
add_action( 'comment_form_logged_in_after', 'comm_rating_rating_field' );
add_action( 'comment_form_after_fields', 'comm_rating_rating_field' );
function comm_rating_rating_field () { ?>
<div class="com_block_star">
<label for="rating">Рейтинг<span class="required">*</span></label>
<fieldset class="comments-rating">
<span class="rating-container">
            <?php for ( $i = 5; $i >= 1; $i-- ) : ?>
                <input type="radio" id="rating-<?php echo esc_attr( $i ); ?>" name="rating" value="<?php echo esc_attr( $i ); ?>" /><label for="rating-<?php echo esc_attr( $i ); ?>"><?php echo esc_html( $i ); ?></label>
            <?php endfor; ?>
<input type="radio" id="rating-0" class="star-cb-clear" name="rating" value="0" /><label for="rating-0">0</label>
</span>
</fieldset>
</div>
<?php
}
//СОХРАНЯЕМ РЕЗУЛЬТАТ
add_action( 'comment_post', 'comm_rating_save_comment_rating' );
function comm_rating_save_comment_rating( $comment_id ) {
    if ( ( isset( $_POST['rating'] ) ) && ( '' !== $_POST['rating'] ) )
    $rating = intval( $_POST['rating'] );
    add_comment_meta( $comment_id, 'rating', $rating );
}
 
//ОБЯЗАТЕЛЬНОСТЬ РЕЙТИНГА
add_filter( 'preprocess_comment', 'comm_rating_require_rating' );
function comm_rating_require_rating( $commentdata ) {
    if ( ! isset( $_POST['rating'] ) || 0 === intval( $_POST['rating'] ) )
    wp_die('Ошибка: Вы не добавили оценку. Нажмите кнопку «Назад» в своем веб-браузере и повторно отправьте свой комментарий с оценкой.');
    return $commentdata;
}
 
//ВЫВОДИМ РЕЙТИНГ В ОПУБЛИКОВАННОМ КОММЕНТАРИИ
add_filter( 'comment_text', 'comm_rating_display_rating');
function comm_rating_display_rating( $comment_text ){
if ( $rating = get_comment_meta( get_comment_ID(), 'rating', true ) ) {
$stars = '<div class="com_star">';
for ( $i = 1; $i <= $rating; $i++ ) {$stars .= '<span class="dashicons dashicons-star-filled"></span>';}
$stars .= '</div>';
$comment_text = $comment_text . $stars;
return $comment_text;
} else {return $comment_text;}
}
 
//ПОДКЛЮЧАЕМ СТИЛИ DASHICONS
add_action( 'wp_enqueue_scripts', 'comm_rating_styles' );
function comm_rating_styles() {
wp_enqueue_style( 'dashicons');
}

Код разбит комментариями, за что отвечает каждая его часть.

//Добавляем рейтинг к комментариям - эта часть кода, добавит в вашу форму комментариев рейтинг. Изначально это просто радио кнопки. Чтобы они превратились в звезды, понадобится еще несколько моментов.
//Сохраняем результат - данная функция, сохраняет результат голосования от комментатора.
//Обязательность рейтинга - эта функция делает наш рейтинг обязательным. Если комментатор не выставит оценку, комментарий не будет отправлен. Если это вам не нужно, то не добавляйте эту часть кода, а так же в самой первой части, можете удалить код - <span class="required">*</span> По-умолчанию, в комментариях WordPress, звездочка означает обязательность заполнения. Если у вас не так, можете поменять.
//Выводим рейтинг в опубликованном комментарии - данная функция выводит рейтинг в опубликованном комментарии. То бишь результат.
//Подключаем стили dashicons - данная функция подключает вшитые в WordPress стили шрифта dashicons. Благодаря ему наши радио кнопки и превратятся в звезды. Но чтобы шрифт заработал, нужен еще один шаг.
Чтобы рейтинг красиво отобразился, ему нужно добавить CSS стили. Можете добавить их в свой файл стилей или в отдельный, а потом его подключить, в общим, как вам удобно.
.all_com_pr span:before{color:#FB9C30;}
.com_block_star{margin:10px 0;}
.comments-rating{border: none;padding: 0;margin-left: 0;}
.comments-rating label{display:inline-block;font-size:18px;}
.rating-container{font-size: 0;unicode-bidi: bidi-override;direction: rtl;}
.rating-container * {font-size: 1.4rem;}
.rating-container > input {display: none;}
.rating-container > input + label {
    font-family:'dashicons';
    display: inline-block;
    overflow: hidden;
    text-indent: 9999px;
    width: 1em;
    white-space: nowrap;
    cursor: pointer;
    margin: 0;
}
 
.rating-container > input + label:before {
    display: inline-block;
    text-indent: -9999px;
    content: "\f154";
    color: #888;
}
 
.rating-container > input:checked ~ label:before,
.rating-container > input + label:hover ~ label:before,
.rating-container > input + label:hover:before {
    content: "\f155";
    color: #FB9C30;
    text-shadow: 0 0 1px #888;
}
 
.rating-container > .star-cb-clear + label {
    text-indent: -9999px;
    width: .5em;
    margin-left: -.5em;
}
 
.rating-container > .star-cb-clear + label:before {
    width: .5em;
}
 
.rating-container:hover > input + label:before {
    content: "\f154";
    color: #888;
    text-shadow: none;
}
 
.rating-container:hover > input + label:hover ~ label:before,
.rating-container:hover > input + label:hover:before {
    content: "\f155";
    color: #FB9C30;
    text-shadow: 0 0 1px #888;
}

На этом этапе, ваш рейтинг уже будет работать и каждый комментатор сможет оставить свою оценку материалу.
Стили можете править под себя и менять внешний вид звезд как вам угодно.

Теперь хочу показать как сделать общую оценку взятую из всех комментариев и выведенную перед контентом, то бишь перед текстом статьи. Для этого вам нужно добавить псоле уже добавленных выше функций, еще парочку:
//ПОДСЧЕТ ОБЩЕЙ ОЦЕНКИ.
function comm_rating_get_average_ratings( $id ) {
    $comments = get_approved_comments( $id );
    if ( $comments ) {
        $i = 0;
        $total = 0;
        foreach( $comments as $comment ){
            $rate = get_comment_meta( $comment->comment_ID, 'rating', true );
            if( isset( $rate ) && '' !== $rate ) {
                $i++;
                $total += $rate;
            }
        }
 
        if ( 0 === $i ) {
            return false;
        } else {
            return round( $total / $i, 1 );
        }
    } else {
        return false;
    }
}
 
// ВЫВОД ОЦЕНКИ ПЕРЕД ПОСТОМ
add_filter( 'the_content', 'comm_rating_display_average_rating' );
function comm_rating_display_average_rating( $content ) {
    global $post;
    if ( false === comm_rating_get_average_ratings( $post->ID ) ) {
        return $content;
    }
    $stars   = '';
    $average = comm_rating_get_average_ratings( $post->ID );
 
    for ( $i = 1; $i <= $average + 1; $i++ ) { $width = intval( $i - $average > 0 ? 20 - ( ( $i - $average ) * 20 ) : 20 );
 
        if ( 0 === $width ) {
            continue;
        }
 
        $stars .= '<span style="overflow:hidden; width:' . $width . 'px" class="dashicons dashicons-star-filled"></span>';
 
        if ( $i - $average > 0 ) {
            $stars .= '<span style="overflow:hidden; position:relative; left:-' . $width .'px;" class="dashicons dashicons-star-empty"></span>';
        }
    }
     
    $custom_content  = '<div class="all_com_pr">Оценка: ' . $average .' ' . $stars .'</div>';
    $custom_content .= $content;
    return $custom_content;
}

//Подсчет общей оценки - эта функция вычисляет среднюю оценку.
// Вывод оценки перед постом - то что получилось выводит перед контентом.
Выводится будет только перед контентом.

Если вас это не устраивает, вы хотите выводить где-то в своем месте, то можете вместо последней функции, добавить немного измененную, которую нужно вызывать в нужном месте.
function comm_rating_display_average_rating() {
global $post;
$stars   = '';
$average = comm_rating_get_average_ratings( $post->ID );
for ( $i = 1; $i <= $average + 1; $i++ ) { $width = intval( $i - $average > 0 ? 20 - ( ( $i - $average ) * 20 ) : 20 );
if ( 0 === $width ) {continue;}
$stars .= '<span style="overflow:hidden; width:' . $width . 'px" class="dashicons dashicons-star-filled"></span>';
if ( $i - $average > 0 ) {
$stars .= '<span style="overflow:hidden; position:relative; left:-' . $width .'px;" class="dashicons dashicons-star-empty"></span>';
}
}
$custom_content  = '<div class="all_com_pr">Оценка: ' . $average .' ' . $stars .'</div>';
echo $custom_content;
}

Что-бы вызвать данную функцию, то есть запустить ее, в нужном вам месте, внутри цикла добавьте такую строку:
comm_rating_display_average_rating();

Данная строка помещается в среду PHP, если у вас HTML, то нужно заключить строку в теги PHP, выглядеть она будет так:
<?php comm_rating_display_average_rating(); ?>

В том месте где вы разместите эту строку, там и появится рейтинг.

Данная система рейтинга по своему интересна и имеет право на существование. С ее помощью можно добиться более точной оценки материала, а в месте с ней и комментарий человека, что ему понравилось или нет в вашем материале.

Важно упомянуть, что данный рейтинг не выводит пустых звезд, то бишь если человек поставит одну звезду, то будет выводится всего лишь 1 звезда, после нее еще 4х пустых не будет.

Добавлено: 18 Июня 2021 04:32:24 Добавил: Андрей Ковальчук

Как отключить редактор Gutenberg для записи или рубрики WordPress

Если по какой то причине вы не хотите использовать плагин Classic Editor, который позволяет создавать и редактировать отдельные записи редактором Gutenberg или классическим, то можно использовать небольшой код, который позволит это сделать. например, если вам всего нужно отключить Gutenberg для одной или двух записей.

Отключаем Gutenberg для одной или нескольких записей
Для отключения редактора Gutenberg только одной для записи, в файл функций вашей текущей темы function.php, нужно добавить небольшой фильтр и внести в него ID нужной вам записи.

Перед изменением function.php, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.

add_filter( 'use_block_editor_for_post', 'disable_gutenberg_for_post', 10, 2 );
function disable_gutenberg_for_post( $use, $post ){
if( $post->ID == 855) 
return false;
return $use;
}

Все что в этом коде вы должны менять, это цифру в третей строке. 855 - это и есть ID вашей записи. Чтобы узнать нужный вам ID, перейдите в список ваших записей, найдите в нем нужную и наведите на ее название курсором.

post=2056 - и есть ID нужной вам записи. Добавляете его вместо 855 и у вашей записи будет классический редактор.

Если вы захотите отключить редактор Gutenberg для нескольких записей, то нужно и их номер добавить в код. Выглядеть это будет примерно так:
add_filter( 'use_block_editor_for_post', 'disable_gutenberg_for_post', 10, 2 );
function disable_gutenberg_for_post( $use, $post ){
if( $post->ID == 855 || $post->ID == 624 ) 
return false;
return $use;
}

$post->ID == 855 - указатель номера записи разделяется со следующим, логическим оператором PHP - ||.

Отключаем Gutenberg для одной или нескольких рубрик
С рубриками, дела обстоят аналогично, меняется код функции для фильтра, но смысл тот же. Он аналогично, с фильтром для записей, добавляется в - function.php. Теперь код выглядит так:
add_filter( 'use_block_editor_for_post', 'disable_gutenberg_for_post', 10, 2 );
function disable_gutenberg_for_post( $use){
if( has_category(1))
return false;
return $use;
}

Как и в прошлых примерах, в третей строке указывается ID нужной рубрики. В примере это - 1. Узнается ID рубрики аналогично с ID записи. Переходите в список рубрик, находите нужную, наводите и в появившейся ссылке внизу страницы увидите ID.

Если решите отключить сразу для нескольких рубрик, то нужно добавить массив, в котором указать через запятую ID рубрик. Выглядит это примерно так:
add_filter( 'use_block_editor_for_post', 'disable_gutenberg_for_post', 10, 2 );
function disable_gutenberg_for_post( $use){
if( has_category(array(1,3)))
return false;
return $use;
}

array(1,3) - и есть наш массив с айди рубрик. Поменяйте на свои и в тех что вы укажите будет выводится классический редактор.

Вот такой получилась еще одна статья об отключении редактора Gutenberg для записи или рубрики. Надеюсь мой цикл статей об этом редакторе вам помог, не знаю будут ли еще статьи о новом редакторе от WordPress, но пока больше новой полезной информации не имею.

Добавлено: 17 Июня 2021 04:32:37 Добавил: Андрей Ковальчук

Плавающая корзина с счетчиком товаров в ней для Woocommerce

Чтобы добавить такую кнопку на свой сайт нужно добавить небольшой код в вашу тему, на которой активирован плагин Woocommerce. Добавлять код нужно, например в файл шапки или подвала. Тогда, ваша иконка плавающая будет отображаться на всех страницах сайта. Лично я добавляю в файл подвала - footer.php. Конкретно, перед функцией - wp_footer();, она есть в любой теме WordPress, в файле footer.php.

<?php 
if (class_exists('WooCommerce' )){
global $woocommerce; ?>
<a href="<?php echo $woocommerce->cart->get_cart_url() ?>" class="fix_cart_btn fz_an">
        <span class="basket-btn__label">Корзина</span>
        <span class="fix_cart_count"><?php echo sprintf($woocommerce->cart->cart_contents_count); ?></span>
</a>
<?php 
} 
?>

Добавлять можно с тегами PHP, можно без, в зависимости от того в какую среду вы добавляете код. В данном примере для HTML среды, если в РНР добавляете, то нужно без первой и последней строки.

По самому коду все просто. Во второй строке мы проверяем активирован ли Woocommerce и существует ли класс WooCommerce. Допустим, у вас не активен плагин, тогда кнопки не будет. Далее, подключаем глобальную переменную $woocommerce, чтобы работала ссылка на корзину и счетчик. Теперь уже начинается код самой ссылки-кнопки. Тут все просто, обычная ссылка, путь которой - корзина вашего сайта.

Внутри ссылки добавлено 2 элемента. Первый это иконка, картинка, слово или то что вы захотите туда добавить. Я добавляю иконку от шрифта Font Awesome, если у вас подключена его 5 версия, то тоже можете добавить ее вместо слова Корзина:
<i class="fas fa-shopping-basket"></i>

Придаем стили нашей кнопке. Она будет фиксированной и плавать в правом нижнем углу. Счетчик товаров в корзине будет над кнопкой в правом ее верхнем углу.
.fix_cart_btn{position:fixed;text-align:center;font-size:10px;color:#fff;line-height:50px;bottom:110px;right:40px;background:#01D19D;border-radius:50px;height:50px;width:50px;z-index:100;}
.fix_cart_btn:hover{color:#fff;background:#E666B1;}
.fix_cart_count{position:absolute;top:2px;right:2px;font-size:11px;line-height:15px;min-width:15px;font-weight:bold;background:#E666B1;-webkit-border-radius:10px;border-radius:10px;}


Вы, конечно же, можете все менять на свой вкус и под свои нужды.

Добавлено: 16 Июня 2021 04:33:53 Добавил: Андрей Ковальчук

Сортировка товаров по наличию в Woocommerce WordPress

Если вы занимаетесь разработкой собственного магазина или помогаете в с этим кому-то, то можете так же столкнутся с такой проблемой, что товары, которых нет в наличии выводятся перед теми, что есть на складе. Таким образом, посетители могут не увидеть ваши горячие предложения и вы потеряете клиента.

Конечно же, вы можете отключить показ товаров которых нет в наличии в настройках плагина Woocommerce. Сделать это можно перейдя по вкладке в консоли - Woocommerce - Настройки - вкладка Товары - вкладка Запасы.

Но, полное отключение товаров, которых нет в наличии, может быть не совсем хорошим шагом. Ведь эти страницы повлекут потом за собой 404 ошибки, выпадут из поисковиков, а значит упадет трафик. Как известно, это не очень хорошо. Вы можете как то привлечь внимание покупателя, даже если товара нет в наличии. Если товара нет временно, можно сделать возможность сообщения, когда тот появится. Если же товар, например, снят с производства, то можно предлагать аналоги или похожие. В общем, не обязательно терять посетителей и удалять страницы. Единственное, это неправильная сортировка, что может отпугнуть посетителей, ее мы и исправим с вами сейчас.

Для этого нужно добавить небольшой код в файл функций. Как я говорил в прошлых статьях, можно добавлять в файл пользовательских функций function.php. Если вы послушались моего совета и создали отдельный файл для Woocommerce, то добавлять нужно в него, чтобы не путать функции темы и Woocommerce, если вы планируете их добавлять много.

Перед изменением function.php или того файла что у вас для функций Woocommerce, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.


// СНАЧАЛА ПОКАЗЫВАТЬ ТОВАР В НАЛИЧИИ
class iWC_Orderby_Stock_Status{
public function __construct(){
    if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
    add_filter('posts_clauses', array($this, 'order_by_stock_status'), 2000);
}
}
public function order_by_stock_status($posts_clauses){
global $wpdb;
if (is_woocommerce() && (is_shop() || is_product_category() || is_product_tag())) {
    $posts_clauses['join'] .= " INNER JOIN $wpdb->postmeta istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";
    $posts_clauses['orderby'] = " istockstatus.meta_value ASC, " . $posts_clauses['orderby'];
    $posts_clauses['where'] = " AND istockstatus.meta_key = '_stock_status' AND istockstatus.meta_value <> '' " . $posts_clauses['where'];
}
return $posts_clauses;
}
}
new iWC_Orderby_Stock_Status;

По коду все просто, добавили в конец файла или куда вам удобно, если вы знаете как работать с кодом и для вас это не проблема.

Добавлено: 10 Июня 2021 07:34:16 Добавил: Андрей Ковальчук

Правильное склонение названий месяцев в датах WordPress

Например, вы опубликовали статью, а дата в ней выглядит примерно так 30 Октябрь 2018. Согласитесь, ведь тридцатое октябрь, как то не звучит, тридцатое октября было бы лучше. Если вы столкнулись с этим и хотите исправить, при этом не менять название месяца на номер или выводить только первые три буквы месяца, то можно добавить одну функцию с несколькими фильтрами.

Для этого вам понадобится добавить немного кода в файл пользовательских функций function.php. Если вы не знакомы с этим файлом и не знаете где добавлять код, то добавляете в самый конец перед закрывающим тегом PHP ?>. Если его нет, то просто в самый конец. Добавить нужно вот такую функцию:

Перед изменением function.php, обязательно сохраните его резервную копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.

function correct_date($cordate = ''){
if ( substr_count($cordate , '---') > 0 ){return str_replace('---', '', $cordate);}
$new_d = array(
'Январь' => 'Января',
'Февраль' => 'Февраля',
'Март' => 'Марта',
'Апрель' => 'Апреля',
'Май' => 'Мая',
'Июнь' => 'Июня',
'Июль' => 'Июля',
'Август' => 'Августа',
'Сентябрь' => 'Сентября',
'Октябрь' => 'Октября',
'Ноябрь' => 'Ноября',
'Декабрь' => 'Декабря'
);
return strtr($cordate, $new_d);
}
add_filter('the_date', 'correct_date');
add_filter('get_the_date', 'correct_date');
add_filter('the_time', 'correct_date');
add_filter('get_the_time', 'correct_date');
add_filter('get_post_time', 'correct_date');
add_filter('get_comment_date', 'correct_date');
add_filter('the_modified_time', 'correct_date');
add_filter('get_the_modified_date', 'correct_date');

У нас есть функция correct_date. Как видите с четвертой строки ее кода начинается замена старых названий на новые. По желанию можете задать свои, например с малой буквы. Данный массив с заменой подойдет для русской версии движка WordPress. Если вы используете английскую, у вас все переведено и нужно исправить дату - то массив будет такой:
$new_d = array(
        "Jan" => "Января",
        "Feb" => "Февраля",
        "Mar" => "Марта",
        "Apr" => "Апреля"
        "May" => "Мая",
        "Jun" => "Июня",
        "Jul" => "Июля",
        "Aug" => "Августа",
        "Sep" => "Сентября",
        "Oct" => "Октября",
        "Nov" => "Ноября",
        "Dec" => "Декабря"
    );

Также можно сделать и для других языков, указывайте изначальное название, а потом то что хотите.

Теперь давайте разберем фильтры, которые подключаются функцию склонения названий. Разберем по порядку:

add_filter('the_date', 'correct_date'); - данный фильтр прикрепляет функцию к выводу на экран или даты публикации поста или группы постов.
add_filter('get_the_date', 'correct_date'); - аналогичный с первым только для функции get_the_date().
add_filter('the_time', 'correct_date'); - данный фильтр прикрепляет функцию склонения к выводу на экран времени (даты) публикации текущей записи в цикле WordPress. the_time - идентична the_date().
add_filter('get_the_time', 'correct_date'); - аналогично с предыдущими.
add_filter('get_post_time', 'correct_date'); - этот фильтр для функции get_post_time, которая получает результат для обработки, а не выводит его на экран.
add_filter('get_comment_date', 'correct_date'); - фильтр для функции get_comment_date, что получает дату указанного комментария.
add_filter('the_modified_time', 'correct_date'); - фильтр для функции the_modified_time, что выводит дату изменения записи.
add_filter('get_the_modified_date', 'correct_date'); - аналогично с предыдущим.
Все эти фильтры затрагивают все функции, что выводят, или получают даты на WordPress. Вы можете не все использовать. Если вам нужно изменить вывод только даты публикации поста и эта дата вызывается только функцией the_date, то вам нужен только первый фильтр и все. Ну и аналогично для остальных.

Вот и все что нужно знать по этому вопросу, теперь вы легко сможете решить проблему со склонением месяцев.

Добавлено: 08 Июня 2021 06:35:41 Добавил: Андрей Ковальчук

Как вывести все записи и разбить их по рубриками WordPress

Нужно было вывести все их и в будущем, чтобы при добавлении новой, она автоматически добавлялась на этой странице в виде ссылки. По сути это была отдельная страница для прайса со списком услуг.

Чтобы сделать подобное, мы будем использовать функцию WordPress - get_categories(). Можете найти о ней информацию, чтобы дополнительно настроить параметры вывода будущего списка. Я же покажу как вывести абсолютно все статьи всех рубрик.

Для начала как раз и настроим параметры get_categories. Создадим переменную $arg_cat и присвоим ей массив с параметрами.

<?php 
$arg_cat = array(
    'orderby'      => 'name',
    'order'        => 'ASC',
    'hide_empty'   => 1,
    'exclude'      => '',
    'include'      => '',
);

В данном масcиве базовые настройки для get_categories. Обратите внимание, что в первой строке у нас тег РНР. Он нужен если вы помещаете код в среду HTML. Если у вас уже среда РНР то этот тег не нужен. Это элементарно, но многие в пешке не замечают, а потом оставляют гневные комментарии о неработоспособности кода. Вы же не один из таких плохих вебмастеров?

orderby - сортируем категории по имени.
order - направление сортировки, указанной в параметре orderby. То бишь от А до Я или от Я до А.
hide_empty - скрывать ли пустые категории. 0 - нет. 1 - да. Рекомендую скрывать, чтобы не выводить просто названия, под которыми не будет списка.
exclude - список ID тех категорий которые нужно исключить из списка. В данном примере - таковых нет.
include - список ID тех категорий из которых только и выводить записи. В данном примере - таковых нет. Можно вывести только с пары рубрик, или с одной, например если в ней много подрубрик.
Теперь присваиваем параметры для get_categories и помещаем ее в переменную - $categories

$categories = get_categories( $arg_cat );

Далее мы проверим не пуста ли переменная $categories, то бишь, если get_categories, согласно заданным в начале параметрам нашла подходящие категории, то мы продолжаем работу. После чего, с помощью foreach, перебираем массив наших категорий что получила get_categories.

Можете прочитать по какому принципу работает foreach, подробно останавливаться на этом не буду. Эта статья материал не для новичков, поэтому если вы не знакомы з foreach. рекомендую ознакомится. Код перебора массива з рубриками, что мы получим, выглядит будет так:

if( $categories ){
    foreach( $categories as $cat ){
     
// ТУТ БУДЕТ БУДУЩИЙ КОД ЦИКЛА ДЛЯ ВЫВОДА СПИСКА
 
}   
} 
?>

Обратите внимание, что в последней строке закрывающий тег РНР. Если вы не в среде HTML, то он не нужен. Выше в статье я писал об этом.

Перебор массива пошел, теперь нужно выводить данные наших рубрик. То бишь - название рубрики и все записи, что в нее входят. В этом нам поможет - WP_Query.

С помощью WP_Query мы выведем цикл. Весь код что мы получим нужно будет поместить внутрь foreach. Для WP_Query можно и нужно задать параметры. С помощью них можно настроить какие записи вы хотите получить, их количество, сортировка и тд. Ознакомьтесь с WP_Query и узнайте все.

В нашем случаи мы будем использовать лишь 2 параметра. один из которых обязателен. Массив с параметрами поместим в переменную - $arg_posts.

$arg_posts =  array(
    'cat' => $cat->cat_ID,
    'posts_per_page' => -1,
);

cat - тот самый обязательный параметр. В нем мы указываем что нужно выводить записи только той категории, которую выбрал перебор foreach из массива категорий. $cat->cat_ID - параметр, который менять нельзя.
posts_per_page - указав значение -1, мы разрешили выводить все записи рубрики. Если хотите выводить только последние 5, то укажите число 5.
Теперь присваиваем параметры для WP_Query и помещаем ее в переменную - $query.

$query = new WP_Query($arg_posts);

Далее уже строим цикл где и выведем все нужные данные.

if ($query->have_posts() ) : ?>
<a href="<?php echo get_category_link( $cat->term_id ); ?>"><h2><?php echo $cat->name; ?></h2></a>
 
<ul>
    <?php while ( $query->have_posts() ) : $query->the_post();  ?>
    <li>
        <a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><h3><?php the_title(); ?></h3></a>
    </li>
<?php endwhile; wp_reset_postdata(); ?>
</ul>         
<?php endif; 

Разбирать подробно код не имеет смысла, это обычный цикл. Сначала проверяем есть ли посты соответствующие нашим параметрам WP_Query. Далее выводим ссылку с названием категории, список записей из которой будет выведен ниже. Вы заметили что мы обернули цикл в теги UL, для того чтобы вывести записи в виде списка, если хотите иначе - учтите. Внутри самого цикла у нас просто ссылка на запись с ее названием. Можете поместить что угодно как и в обычном цикле - миниатюру, отрывок текста, произвольные поля и тд. Все как и в обычном цикле на главной, в категориях, архивах и тд.

Теперь соберем все в кучу, чтобы получить готовый результат.

<?php 
//НАЧАЛО СПИСКА
 
$arg_cat = array(
    'orderby'      => 'name',
    'order'        => 'ASC',
    'hide_empty'   => 1,
    'exclude'      => '',
    'include'      => '',
);
$categories = get_categories( $arg_cat );
 
if( $categories ){
    foreach( $categories as $cat ){
        $arg_posts =  array(
                'posts_per_page' => -1,
                'cat' => $cat->cat_ID,
            );
    $query = new WP_Query($arg_posts);
 
if ($query->have_posts() ) : ?>
<a href="<?php echo get_category_link( $cat->term_id ); ?>"><h2><?php echo $cat->name; ?></h2></a>
 
<ul>
    <?php while ( $query->have_posts() ) : $query->the_post();  ?>
    <li>
        <a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><h3><?php the_title(); ?></h3></a>
    </li>
<?php endwhile; wp_reset_postdata(); ?>
</ul>         
<?php endif; 
 }  } 
 
// КОНЕЦ 
?>

Данный код можно поместить в любое место темы, где хотите вывести данный список. Учтите только среда РНР или HTML.

Так же, могу предложить вам для того, чтобы посмотреть на результат, добавить страницу на сайте на которой будет пример. Для этого скачайте файл ниже, это шаблон страницы с встроенным списком. Поместите его в папку с темой. Шаблон называется - Страница со всеми записями. Далее создайте новую страницу в консоли вашего сайта WordPress. После чего в параметрах страницы укажите шаблон - Страница со всеми записями.

Сохраните настройки и смотрите страницу. Функция выведет все рубрики и записи к ним что есть на сайте.

Добавлено: 18 Мая 2021 06:35:31 Добавил: Андрей Ковальчук

Как создать бота в Телеграм для получения оповещений с форм сайта

В принципе, данная инструкция может быть актуальной и для других форм и плагинов, для которых нужен бот в Телеграм. Суть у всех одна, боты создаются одинаково. Главное что нужно после создания это Токен вашего бота и ID чата куда он добавлен или чата самого бота.

Если подключить к форме отправку на Телеграм или вы используете один из моих плагинов, то вы будете получать оповещения прям в мессенджер.

Как создать бота
1. Первым делом, у вас должен быть установлен мессенджер Telegram. На телефоне или ПК, а желательно и там и там. Я буду показывать на примере ПК, но на телефоне все то же самое.

2. Далее нужно найти через поиск в мессенджере главного бота, что создает других. Это BotFather - единственный бот, который управляет ими всеми. Используйте его для создания новых учетных записей ботов и управления существующими ботами. Найдите и нажмите на него, чтобы открылся его чат.

3. Теперь нужно запустить BotFather. Для этого нужно нажать кнопку ЗАПУСТИТЬ внизу чата или написать в чат /start, если вместо кнопки у вас поле для ввода.

4. После запуска появится список команд, переместитесь в начало сообщения и нажмите на команду /newbot или просто пропишите эту команду через поле сообщения.

5. Теперь BotFather предложит вам назвать своего бота. Это название вы будете видеть в списке контактов. В примере бот назван как testmailbot. Можете называть как угодно, например: Бот для формы контактов, Бот какого-то плагина, Мой бот с сайта и тд. Без разницы, лишь бы вы понимали что это за бот и если у вас их будет много, вы их не путали.

6. Далее BotFather предложит вам указать имя бота. Вот тут нужно быть внимательным. Имя бота вводится только латиницей и в конце должно заканчиваться на bot. В примере это testmailbot_bot. Задавайте что хотите, если имя будет существовать, BotFather вас предупредит. Так что придумайте что-то уникальное.

7. Если вы задали правильное имя, то BotFather напишет вам, что все готово и вашему боту присвоен Токен, который понадобится для доступа через HTTP API. Этот токен нам и нужен для того, чтобы формы отправляли свои данные в Телеграм.

8. Теперь найдем и запустим нашего бота. Для этого в поиске контактов в Telegram найдите бота и нажмите на него.

9. Так же нужно запустить бота. Внизу есть кнопка ЗАПУСТИТЬ или напишите в чат /start, если вместо кнопки у вас поле для ввода.

Это еще не конец. Если вы не хотите создавать групповой чат для многих ботов, если у вас одна форма или один плагин или вы хотите чтобы данные со всех форм приходили только к одному боту, что вполне нормально, то можно пропустить следующие 4 шага и перейти к пункту - 12.

8. Чтобы добавить бота в групповой чат, если вы захотите иметь несколько ботов для нескольких форм, то вам нужно перейти в настройки Telegram и выбрать пункт - Создать группу.

9. Далее нужно ввести название для группы. Вводите какое вам нравится.

10. Теперь нужно добавить участников в группу, то бишь нашего бота. Есть 2 способа. Можно просто на странице самого бота нажать на его настройки и там выбрать пункт Добавить в группу. После чего вам предложит ваши собственные группы. Выберите ту что создали только что для ботов и все. Второй вариант - нажмите на настройки группы и выберите пункт - Добавить участников.

11. Перед вами появится окно поиска, введите в поле имя своего бота, то что вводили в пункте 6. Возможно, найдется несколько ботов, но только у одного будет точное название, в нашем примере это @testmailbot_bot. Когда найдете своего бота, выделите и нажмите кнопку - Добавить.

12. Последнее что нужно сделать чтобы передавать данные с форм которые поддерживают передачу на Телеграм, это получить ID чата. Тут два варианта. Если вы используете только чат бота, то ID один, если чат группы с ботами, то ID другой. Чтобы узнать нужный ID, нужно в адресной строке браузера перейти по ссылке, которую нужно сформировать.

https://api.telegram.org/botХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ/getUpdates

Вместо ХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ нужно вставить тот токен, который вам дал BotFather в пункте 7, этой инструкции.

Если вы используете мой плагин с возможностью отправки оповещений на телеграмм, то можете прям в настройках плагина перейти по готовой ссылке, главное сначала добавьте в нужное поле токен и сохраните, после ссылка станет рабочей.


12. Последнее что нужно сделать чтобы передавать данные с форм которые поддерживают передачу на Телеграм, это получить ID чата. Тут два варианта. Если вы используете только чат бота, то ID один, если чат группы с ботами, то ID другой. Чтобы узнать нужный ID, нужно в адресной строке браузера перейти по ссылке, которую нужно сформировать.

https://api.telegram.org/botХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ/getUpdates

Вместо ХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ нужно вставить тот токен, который вам дал BotFather в пункте 7, этой инструкции.

Если вы используете мой плагин с возможностью отправки оповещений на телеграмм, то можете прям в настройках плагина перейти по готовой ссылке, главное сначала добавьте в нужное поле токен и сохраните, после ссылка станет рабочей.

Рекомендую открывать ссылку в браузере Mozilla Firefox. В нем данные отображаются сгруппировано и очень легко понять где нужный ID. Где чат бота, где чат группы, если вы в нее добавили бота.


Как видите, по изображению видно что вначале показывает ID чата бота с моим именем, у вас будет с вашим, после того как вы напишите что-нибудь боту. Ну а далее ID группы, в которую мы добавили нашего бота в пункте 9/10.

Много непонятного, но среди этого кода нужно всего одно значение. Какое, зависит от того используете ли вы лишь бота или чат. Если только бота то ищите, ID такого типа - "id":380199086,"first_name". И з этого вам нужно только номер 380199086. Если у вас группа с ботами, то такого "id":-1011500162037. У ID груп стоит черточка в начале. Вам, опять же, нужен номер только с черточкой -1011500162037. Если, вдруг, вы добавили токен и ID в форму, а сообщения не приходят, то попробуйте другой. Сложностей не должно возникнуть.

После успешного добавления испытайте плагин или форму. Вы должны получить оповещение на Telegram, в моем примере, это выглядело так:

Теперь у вас есть и токен и нужный ID. Они вам потребуются чтобы их добавить в настройках моих плагинов, других разработчиков, в свои собственные формы, если вы такие создаете.

Добавлено: 15 Мая 2021 07:58:40 Добавил: Андрей Ковальчук

Система лайков или кнопка мне нравится c использованием cookies на WordPress

Если совпадение находилось, то голос не засчитывался, так работает фильтр, чтобы не было накруток. Мне это не понравилось, потому как идея засорения базы данных мусором - такое себе. Поэтому я решил переделать прошлый материал под использование cookies. С их помощью и будет хранится информация - голосовал ли посетитель ранее.

Чтобы это сделать, нужно выполнить первые два пункта прошлой статьи. Сначала инициализировать скрипт - post-like.js. Далее добавляете две строки add_action, где мы нашу функцию по подсчету голосов вешаем на указанный хук. там все расписано и просто.

Третий шаг в прошлой статье - это подключение нашей функции подсчета и записи голосов post_like(). Ее уже с той статьи подключать не надо. Для способа с cookies у нас будет упрощенная ее версия. Но прочитать ее полностью. чтобы понять устройство и принцип стоит, потому как дальше у нас измененные скрипты но смысл их тот же что и там и там более подробно расписано.

Если добавили подключение post-like.js с дополнительные данными для аякса и повесили будущую функцию на хук. То после добавляете новую функцию, переделанную - post_like().

function post_like(){
$nonce = $_POST['nonce'];
if(!wp_verify_nonce( $nonce, 'ajax-nonce')) die ( 'Ошибка!');
if(isset($_POST['post_like'])){
$post_id = $_POST['post_id'];
$meta_count = get_post_meta($post_id, "votes_count", true);
update_post_meta($post_id, "votes_count", ++$meta_count);
echo $meta_count; 
}
exit;
}

Как видите, она схожа с прошлой, но с нее вырезано все что касается проверки и записи полей для IP адреса. Расписывать нет смысла такие же строки расписаны в прошлой статье. Функция просто при запуске получает ID статьи где нажали на кнопку, и в ее произвольное поле, которое называется - votes_count, записывает значение на 1 больше.

После функции подсчета, нам нужна новая функция вызова самой кнопки уже на сайте. Той кнопки по нажатию на которую и будет подсчет. подключаете ее после прошлой в том же function.php.
function getPostLikeLink($post_id){
$vote_count = get_post_meta($post_id, "votes_count", true);
//НЕАКТИВНАЯ КНОПКА
$output = '<div class="nopost-like"><span>Нравится</span><span class="count">'.$vote_count.'</span></div>';
//АКТИВНАЯ КНОПКА
$output .= '<div class="post-like"><span class="like_ico" data-post_id="'.$post_id.'">Нравится</span><span class="count">'.$vote_count.'</span></div>';
return $output;
}

getPostLikeLink - теперь тоже новая. Так как нет проверки по айпи, она выглядит иначе. По сути она выводит сразу 2 кнопки. Активную и нет, ту на которую нажать нельзя.

Неактивная имеет класс у родительского контейнера nopost-like, а активная - post-like. Это нужно учесть, эти классы понадобятся далее.
// В СРЕДУ PHP
echo getPostLikeLink(get_the_ID());
//  В СРЕДУ HTML
<?php echo getPostLikeLink(get_the_ID()); ?>

Теперь вернемся к post-like.js. В прошлой статье в нем был один код, теперь немного измененный уже с учетом cookies. Создаете или открываете, если создали и заменяете содержимое или добавляете новое если он пуст:
jQuery(document).ready(function($){
$(".like_ico").click(function(){
var pathToMyPage = window.location.pathname;
$.cookie("post-like-count", "1", { expires:1, path: pathToMyPage }); 
heart = $(this);
post_id = heart.data("post_id");
$.ajax({
type: "post",
url: ajax_var.url,
data: "action=post-like&nonce="+ajax_var.nonce+"&post_like=&post_id="+post_id,
success: function(count){
if(count != "already"){
heart.addClass("voted");
$(".count").text(count);
$('.post-like').hide();
$('.nopost-like').show();
}
}
});
return false;
});
 
if ( $.cookie("post-like-count") == null){
    $('.post-like').show();
    $('.nopost-like').hide();
}else{
    $('.post-like').hide();
    $('.nopost-like').show();
}
 
 
});

Скрипт не сложный, кто разбирается поймет все сразу, для остальных немного распишу.

Во второй строке мы запускаем событие после нажатия на кнопку с классом like_ico. В нашей кнопке это слово - Нравится.
В третей строке создаем переменную, с ссылкой на текущую страницу - pathToMyPage . Это для куков, чтобы они записались только для статьи где нажата кнопка, а не для всех кнопок на сайте.
В четвертой строке - создаем имя для куков - post-like-count и значение - 1.

Если кнопка нажата - кукам задается значение 1 и кнопка в будущем станет неактивна. Так же expires, задается 1, это один день. То бишь куки хранятся сутки после они сотрутся и кнопку можно нажать повторно. Если нужно больше дней, укажите свое значение. Ну и в конце переменная с прошлой строки указывает для какой страницы хранить куки.

Далее идет уже аякс отправка нажатия, подсчет голосов, запись в бд и тд, подробнее в прошлой статье. После успешной отправки запроса выполняем определенные действия.
В 14 строке обновляем значения счетчиков у всех блоков с классом count. Так что в функции вывода кнопки учтите это и не меняйте класс или меняйте везде.
В 15 $('.post-like').hide(); - скрываем активную кнопку, которая позволяет увеличивать значение счетчика на 1.
И в 16 строке $('.nopost-like').show(); - показываем неактивную кнопку, нажать которую нельзя. В принципе все с событием по нажатию.
Далее с 23 строки мы проверяем после загрузки страницы, как только человек обновит страницу или впервые зайдет - есть ли у него куки к данной странице. Если нет - не показывать активную и показывать неактивную и в противном случаи - наоборот.
На этом со скриптом все. Но есть еще один важный момент. Куки не будут записываться без специального скрипта куков. Он может быть подключен к вашему сайту ранее, например если вы используете чужую тему, которая уже использует его или какой-то плагин например. На этом этапе вы можете проверить работу кнопки, если нажатия можно совершать множественное количество и кнопка не становится - неактивной, то значит вам не повезло :). Нужно выполнить последний шаг.

Вам нужно скопировать следующую строку скрипта. Она длинная, обязательно скопировать все!
jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000))}else{date=options.expires}expires='; expires='+date.toUTCString()}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('')}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break}}}return cookieValue}};

Скопированный код нужно добавить в отдельный файл и подключить к своей теме или добавить в конец уже подключенного файла, но делать это нужно, если вы знаете как правильно это делать иначе может перестать работать и скрипт уже добавленный в файл ранее.

После подключения скрипта записи куков - кнопка должна срабатывать только один раз для одной записи.

Что касается стилей, то тут по желанию.

Добавлено: 05 Мая 2021 06:49:34 Добавил: Андрей Ковальчук

Как добавить время чтения к записи WordPress

Недавно мне тоже была поставлена задача сделать вывод такой информации на одной из тем. Раньше не сталкивался с подобной задачей, но видел подобное не раз.

Немного изучив материал, я понял, что нужна небольшая функция ибо вариант с плагином отпал сразу. Не настолько тут все сложно, чтобы подключать тяжелую артиллерию. Немного погуглив, был найден кусок кода из одной забугорной темы. Ее разработчик предоставил этот фрагмент, чтобы другие могли воспользоваться. Но с ним возникла проблема, он почему то не выводил ничего.

Изучив код, я разорался в нем и немного переделал. Там использовалась функция для подсчета слов в тексте, которая не работает с кириллицей, только латиница, поэтому у меня оно и не считало как нужно. Автор того кода использовал метод подсчета через - str_word_count().

Немного изменив код и адаптировав его под кириллицу, у меня получилась такая, готовая функция.

function estimated_reading_time(){
$post = get_post();
$postcnt = strip_tags( $post->post_content );
$words = count(preg_split('/\s+/', $postcnt));
$minutes = floor( $words / 120 );
$seconds = floor( $words % 120 / ( 120 / 60 ) );
if (1 <= $minutes){$estimated_time = $minutes . ' мин на чтение' . ($minutes == 1 ? '' : 's');}
else{$estimated_time = $seconds . ' сек на чтение' . ($seconds == 1 ? '' : 's');}
echo $estimated_time;
}

Давайте разберем ее, чтобы понять как она устроена.

1. $post = get_post(); - Создаем переменную $post, которая будет содержать в себе текст записи.
2. $postcnt = strip_tags( $post->post_content ); - Новая переменная в которой из текста записи убираем все теги, оставляя голый текст.
3. $words = count(preg_split('/\s+/', $postcnt)); - Третья переменная, в которой и ведется подсчет слов используя вторю переменную.
4. $minutes = floor( $words / 120 ); - Переменная в которой мы вычисляем минуты, что понадобятся для чтения текста записи. Тут используется простая 5. формула. Берем весь текст и разделяем на среднюю скорость чтения - 120 слов в минуту. Если хотите сменить скорость, укажите свое число.
6. $seconds = floor( $words % 120 / ( 120 / 60 ) ); - Переменная, для вычисления секунд. если текст короткий. Ну и если хотите можно указывать время чтения статьи вместе с секундами, например - 2мин 32сек, если вам нужна прям такая точность.
7. Дальше, мы просто создаем условие, если время чтения больше минуты то выводим текст в минутах, в противном случаи в секундах
8. Ну и в конце выводим результат.

Как упомянул выше, если хотите то время можно выводить с секундами, просто замените седьмую строку, где начинается условие, на немного другой код.
if (1 <= $minutes){$estimated_time = $minutes . ' мин' . ($minutes == 1 ? '' : 's') . ', ' . $seconds . ' сек' . ($seconds == 1 ? '' : 's');}

Данная функция добавляется в файл function.php или другой файл вашей темы, где вы добавляете пользовательские функции. Добавляете в самый конец перед закрывающим тегом PHP ?>. Если его нет, то просто в самый конец.

Перед изменением function.php, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было. Так же, можете использовать дочернюю тему.


Чтобы вывести время в шаблоне вашей темы, в том место где хотите видеть надпись с временем, просто добавьте вызов функции. Это может быть single.php,category.php,content.php и тд. Все зависит от вашей темы, сказать точно я не могу.
bm_estimated_reading_time();

Если добавляете в среду HTML, то не забудьте теги PHP и код будет таким:
<?php bm_estimated_reading_time();?>

Добавлено: 29 Апреля 2021 06:36:44 Добавил: Андрей Ковальчук

Как переименовать вкладки, табы на странице товара в магазине Woocommerce WordPress

Речь пойдет о трех стандартных вкладках, что размещены на странице товара Woocommerce. Это вкладки - Описание, Детали и Отзывы. Такое может понадобится, например, если у вас появится вопрос - как переименовать вкладку детали на Характернистики.

Естественно, текст на вкладках можт быть любым. Давайте же разберем как это сделать.

Переименование делается благодаря использованию фильтра woocommerce_product_tabs для woocommerce. Данный фильтр, как и все функции нужно добавлять в файл пользовательских функций. Как я говорил в прошлых статьях, можно добавлять в файл пользовательских функций function.php. Если вы послушались моего совета и создали отдельный файл для Woocommerce, то добавлять нужно в него, чтобы не путать функции темы и Woocommerce, если вы планируете их добавлять много.

Перед изменением function.php или того файла что у вас для функций Woocommerce, обязательно сохраните его копию, чтобы в дальнейшем, в случаи ошибки, вернуть все как было.

add_filter( 'woocommerce_product_tabs', 'wootabs_rename', 98 );
function wootabs_rename( $tabs ) {
$tabs['additional_information']['title'] = __( 'Вместо Деталей' );
$tabs['description']['title'] = __( 'Вместо Описания' );
$tabs['reviews']['title'] = __( 'Вместо Отзывов' ); 
return $tabs;
}

По коду все просто. Первая строка мы запускаем наш фильтр с функцией wootabs_rename, которую ниже создаем во второй строке.

1. $tabs['description'] - вкладка описание.
2. $tabs['additional_information'] - вкладка Детали
3. $tabs['reviews'] - вкладка Отзывы

В этих трех строках мы и меняем название, а конкретнее пишите свои названия в место моих - Вместо Описания, Вместо Деталей, Вместо Отзывов. Можно удалить ненужные,если переименовать нужно только одну вкладку, а остальные оставить без изменений или использовать все строки, тут все зависит от ваших нужд.

В предпоследней строке возвращаем новые название с помощью return.

Так же, если по каким то причинам данный фильтр не сработал, можно сделать фильтр для каждой вкладки отдельно. Тогда код будет следующим:
add_filter( 'woocommerce_product_description_tab_title', function(){
    return 'Вместо Описания';
} );
add_filter( 'woocommerce_product_additional_information_tab_title', function(){
    return 'Вместо Детали';
} );
add_filter( 'woocommerce_product_reviews_tab_title', function(){
    return 'Вместо Отзывов';
} );

Тут тоже все просто. Три разных фильтров для трех вкладок. Просто добавьте любой из трех, два или все сразу и напишите свое название вкладки.

Как видите, нет ничего сложного. Надеюсь, эта статья будет вам полезна и поможет вам в вашем вопросе.

Добавлено: 28 Апреля 2021 06:45:22 Добавил: Андрей Ковальчук