Как скопировать жесткий диск с OS linux

Бывает необходимо иметь резервную копию диска, на случай поломки или выхода из строя. Также возможна ситуация, когда Вы просто хотите перейти на диск большего размера. Как раз у меня возникла такая ситуация и на диск ssd диск 128 гигабайт перестал влезать необходимый софт. Для этого был прикуплен ssd на 250Gb. Установленная операционная система — Ubuntu 16.04 .
Немного порывшись в интернете решил, что самым простым способом будет исользовать специально предназначенную для этого программу clonezilla. Таким образом алгоритм перехода на новый диск будет таким

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

2. Делаем образ clonezilla live. Для этого можно воспользоваться специальной утилитой tuxboot.
2.1 устанавливаем Tuxboot , на официальном сайте tuxboot написано как это сделать. Я выбрал
установку через ppa.
2.2 Запускаем просто набрав в командной строке tuxboot. Вас спросят пароль администратора.
2.3 Интерфейс будет достаточно понятным, выбираем образ и флешку, и далее ОК

3. Загружаемся с загрузочной флешки (В биосе надо нажать кнопку прерывания для выбора приоритета загрузки, на плате B350M PRO-VDH это F11)
3.1 Далее идут простые вопросы, выбираем с диска на диск и в самом простом случае выбираем все дефолтные настройки. Опять же особенности каждой опции можно узнать на официальном сайте clonezilla .

Готово, теперь у Вас есть копия диска. На этом можно закончить, но добавлю пункт 4 со звёздочкой

4*. Редактирование разбиения диска или партиций. Как было замечено, мне необходимо было перейти на диск большего объёма, бывают случаи что надо например сделать резервную копию на диск меньшего объёма. В таком случае в clonezilla надо выбрать режим «expert mode». И тогда в одном из окон вас спросят про разделы. Выбираем чтобы разделы создавались пропорционально.

Таким образом за 4 шага мне удалось перейти на новый, более быстрый и объёмистый диск на линуксе.

Простой пример нейронной сети на keras и tensorflow с тремя слоями

В данном посте будет показано, как инициализировать нейроннуй сеть на python, задать слои, обучить и получить предсказанные результаты. Пример сделан на python3, а в прослойке между tensorflow установлена библиотека Keras. Чтобы было понятнее — все входные параметры будут подписаны.
И так, нейронные сети очень мощный и не тривиальный инструмент в руках дата-инженера. Однако большинство продвижений в области машинного обучения в последние годы связано именно с нейронными сетями.
Установка:
keras и tensorflow ставится через pip: pip3 install keras и pip3 install —upgrade tensorflow
Отмечу, что здесь мы установили tensorflow для CPU, использование GPU даёт существенный прирост скорости, но и поставить посложнее.

Общий путь
1) Создание модели
2) Компилирование модели
3) Загрузка/подготовка данных
4) Обучение нейронной сети
5) Предсказание

Импорт библиотек:
import numpy as np
# Для создания простых моделей используют Sequential,
# При использовании Sequential достаточно добавить несколько своих слоев.
# Для более сложных моделей уже надо будет использовать Functional API
from keras.models import Sequential
from keras.layers import Dense # Dense — один из типов слоёв в Keras для создания слоя нейронов

Использовать будем бинарную классификацию, т.е. по набору фич надо определить принадлежит ли объект классу или нет.
Данные можете взять свои или например из этого файла data.txt. В нём есть 8 фич, а последний столбец показывает принадлежность классу

from keras.models import Sequential
from keras.layers import Dense
import numpy as np

# загружаем данные с фичами
dataset = np.loadtxt("data.txt", delimiter=",")
# Первые 8 столбцов в примере отвечают за фичи, последний же за класс, разбиваем 
X = dataset[:,0:8]
Y = dataset[:,8]

# Создаём модель!
model = Sequential()
# Добавляем первый слой Dense, первое число 12 - это количество нейронов, 
# input_dim - количество фич на вход
# activation -  функция активации, полулинейная функция max(x, 0) 
# именно полулинейные функции позволяют получать нелинейные результаты с минимальными затратами
model.add(Dense(12, input_dim=8, activation='relu'))
# добавляем второй слой с 8ю нейронами
model.add(Dense(8, activation='relu'))
# на выходе при бинарной классификации, функцию активации чаще всего используют sigmoid , реже softmax
# Компилирование модели. binary_crossentropy - опять же не случайно, а т.к. у нас два класса.
# Метрика accuracy используется практически для всех задач классификации
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# Наконец дошли до обучения модели, X и Y - понятно, 
# epoch - максимальное количество эпох до остановки
# batch_size - сколько объектов будет загружаться за итерацию
model.fit(X, Y, epochs=15, batch_size=10,  verbose=2)
# Предсказание
predictions = model.predict(X)

Создание высокоточной нейронной сети - непростое задание. Порой хорошо работающие сетки получают случайно, и сложно объснить почему именно они хорошо работают. Поэтому дальше можете поиграть с разными параметрами. Заглядывая наперед - один из способов подбора гиперпараметров нейронной сети - использование библиотеки hyperopt, которая пытается сделать предсказать результирующую функцию, вместо перебора всех параметров, т.к. перебор параметров может быть уж сильно долгим.
Таким образом на выходе мы получаем обученную нейронную сеть на keras . Для использования этой сети в будущем, проще всего использовать model.save(filepath) . Обращу внимание, что picke не рекомендуется. А для загрузки сохраненной ранее модели: keras.models.load_model(filepath).

Определение языка текста на python с помощью langdetect

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

$ pip install langdetect

Заметим, что код портирован на питон из гугловской библиотеки language-detection, поэтому качество распознавания языка находится на уровне, во всяком случае у меня пока особых претензий не было.
Далее, всё весьма стандартно, импортируем библиотеку и вызываем функцию «детектирования языка», пример:

from langdetect import detect
detect("здесь произвольный фрагмент текста на вход")
# результат: ru

По умолчанию поддерживается 55 языков, двухбуквенные коды взяты из стандарта кодов языков, и если быть подробнее, то они такие: af, ar, bg, bn, ca, cs, cy, da, de, el, en, es, et, fa, fi, fr, gu, he, hi, hr, hu, id, it, ja, kn, ko, lt, lv, mk, ml, mr, ne, nl, no, pa, pl, pt, ro, ru, sk, sl, so, sq, sv, sw, ta, te, th, tl, tr, uk, ur, vi, zh-cn, zh-tw

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

from langdetect import detect, detect_langs
from langdetect import DetectorFactory
DetectorFactory.seed = 0

detect_langs("Otec matka syn.") 
# результат [sk:0.572770823327, pl:0.292872522702, cs:0.134356653968]

Как видим, detect_langs определил не только языки, использованные в тексте, но ещё и их вероятности. Также возможно у Вас возник вопрос, зачем я использовал DetectorFactory? Дело в том, что алгоритм не является детерминированным, т.е. при разных запусках он может выдавать разные результаты. Если Вы хотите избежать разнозначности при разных запусках, то советую использовать DetectorFactory.seed = 0, если же такой необходимости нет, то лучше сэкономить пару строк.

Далее подметим, что detect_langs вернул не просто языки, а лист объектов Language, и возникает вопрос, как же получить языки и вероятности из этого листа? Смотрите пример:

from langdetect import detect_langs

list_of_languages = detect_langs("Здесь некий текст") 
for l in list_of_languages:
    # используем атрибуты lang и prod
    print(l.lang, l.prob)
    # результат: ru , 0.99

Определение языка может быть полезно при реализации поиска (для выдачи более релевантных результатов), а также для запуска языко-зависимых программ. Как видите с помощью langdetect определить язык можно всего в 2 строки!

Пример использования CountVectorizer в sklearn

Одна из первых концепций обрабтки естественных языков Bag-of-Words — это статистический анализ, анализирующий количественное вхождение слов в документах. Не смотря на то, что подход сформирован весьма давно, он отлично подходит для первичной обработки текстов и быстрого прототипирования.

Модуль CountVectorizer в sklearn как раз подзволяет сконвертировать набор текстов в матрицу токенов, находящихся в тексте. Также имеется много полезных настроек, например можно задать минимальное количество необходимое для появления токена в матрице и даже получить статистику по n-граммам. Следует учитывать, что CountVectorizer по умолчанию сам производит токенизацию и выкидывает слова с длиной меньшей чем два.

Пример:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

# инициализируем
vectorizer = CountVectorizer()
# составляем корпус документов
corpus = [
  'слово1 слово2 слово3',
  'слово2 слово3',
  'слово1 слово2 слово1',
  'слово4'
]
# подсчитываем
X = vectorizer.fit_transform(corpus)

# таким образом будет подсчитана следующая структура:
#        | слово1 | слово2 | слово3 | слово4
# текст1 |   1    |    1   |   1    |   0
# текст2 |   0    |    1   |   1    |   0
# текст3 |   2    |    1   |   0    |   0
# текст4 |   0    |    0   |   0    |   1

# чтобы получить сгенерированный словарь, из приведенной структуры CountVectorizer, стоит отметить что порядок совпадает с матрицей
vectorizer.get_feature_names()  # ['слово1', 'слово2', 'слово3', 'слово4']

# чтобы узнать индекс токена в словаре
vectorizer.vocabulary_.get('слово3') # вернет 2

# показать матрицу
X.toarray()

# теперь можно быстро подсчитать вектор для нового документа
vectorizer.transform(["слово1 слово4 слово4"])  # результат [[1 0 0 2]]

# чтобы узнать количественное вхождение каждого слова:
matrix_freq = np.asarray(X.sum(axis=0)).ravel()
final_matrix = np.array([np.array(vectorizer.get_feature_names()), matrix_freq])

Один из минусов, что добавлять новые слова в словарь не получится, необходимо сразу указать все документы.
Второй из минусов, отчасти идущий от первого — плохая масштабируемость на большой набор текстов. Есть вероятность натолкнуться на MemoryError уже при десятке тысяч документов. Поэтому либо надо ограничивать количество фич/токенов для попадания в словарь с помощью настройки max_features или же использовать другую библиотеку. Однако для нескольких тысяч можно весьма быстро получить результат и далее использовать фичи например для классификации или кластеризации документов.

Постинг в канал telegram с помощью python или бот telegram в 3 строчки

Предположим надо написать телеграмм бота, который при появлении свежей новости на сайте пишет в канал. Практическое применение для меня было в том, что на одном сайте изредка появляется важная информация, которую пропускать не хотелось, но и постоянно мониторить сайт тоже. В итоге захотелось написать максимально простой и минималистичный python скрипт, выполнющий задачу постинга в канал telegram и не использующий даже базу данных. Такая простота достигается следующим образом: по крону раз в сутки запускается программа, которая вытягивает все новости за вчерашний день. Непосредственно отправление сообщения в канал занимает 3 строчки, подробнее об этом конце, а сейчас разделим задачу на несколько логических последовательных подзадач:

  1. Отслеживание появления новости

    • 1.1 Запрос html страницы (использование бибиотеки requests)
    • 1.2 Парсинг html страницы (здесь будем использовать питон библиотеку BeautifulSoup)
    • 1.3 разбивка списка новостей на старые и новые публикации
  2. Отправка сообщения в телеграм канал

    • 2.1 Создание канала а также бота с помощью BotFather и добавление бота в администраторы канала
    • 2.2 Выбор библиотеки и её инициализация с помощью токена telegram, полученного от все того же BotFather (в нашем случае это библиотека python-telegram-bot )
    • 2.3 Отправка сообщения.
  3. Настройка обработчика cron

    • раз в сутки: «1 12 * * * /path/to/bot.py >/dev/null 2>&1″
# подключаем библиотеки
import requests
import random
from bs4 import BeautifulSoup
from datetime import date, timedelta
import telegram

# будем брать информацию за вчерашний день
yesterday = date.today() - timedelta(1)
yesterday_str = yesterday.strftime('%d.%m.%Y')

# На некоторых сайтах стоит минимальная защита и они не отдают контент без user-agent
headers = {'user-agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'}
# чтобы избежать кэширования на любом уровне, на всякий случай добавим случайно число
r = requests.get('http://здесь-название-сайта.ru/?r='+str(random.random()))

# парсинг заголовков и времени создания новости
soup = BeautifulSoup(r.text, 'html.parser')
h2s = soup.find_all('h2', class_='PostHeaderIcon-wrapper')
h2s = [x.text.strip() for x in h2s]
times = soup.find_all('div', class_='PostHeaderIcons metadata-icons')
times = [x.text.strip() for x in times]

for k, t in enumerate(times):
    if t.split()[0] == yesterday_str:  # если новость за вчера, то постим
        # Непосредственно здесь идет отправка. Инициализируем бота с помощью токена
        bot = telegram.Bot(token='123456789:AABBCCDDefgh_mnaviwuue_DP865Y')
        chat_id = '@here_some_channel_to_post'
        # тест новости
        chat_text = 'Новая новость на <a href="http://здесь-урл-сайта.ru">сайте</a>:\n {}'.format(h2s[k])
        # отправка поста в канал. Маленькая тонкость - используется HTML разметка
        bot.send_message(chat_id=chat_id, text=chat_text, parse_mode=telegram.ParseMode.HTML)

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

import telegram
bot = telegram.Bot(token='123456789:AABBCCDDefgh_mnaviwuue_DP865Y')
bot.send_message(chat_id='@here_some_channel_to_post', text='some text to post')

					

Как создать requirements.txt файл для python программы

Требование наличия в корне файла requirements.txt — достаточно распространенное среди заказчиков. Это и не удивительно — ведь для того чтобы быстро установить все требуемые библиотеки python в новом окружении достаточно выполнить команду pip install -r requirements.txt .

Рассмотрим несколько вариантов.
Вариант первый — вручную. Минусы думаю объяснять не надо, мало того что вы можете ошибиться в названиях и версиях, но также легко и пропустить библиотеку.

Вариант второй — стандартом pip. Выполнив команду pip freeze > requirements.txt вы сразу получите файл в требуемом формате. Если есть уверенность, что у Вас не установлено никаких лишних библиотек — то это самый оптимальный способ. Недостаток этого способа один — в файле будут отображены абсолютно все библиотеки python, уже установленные ранее и никак не относящиеся к текущему проекту.

Вариант третий — использовать дополнительную библиотеку для генерации файла зависимостей. В данном случае надо сразу смотреть на кроссплатформенность, так как не все библиотеки могут работать с windows/unix . Самым распространненым вариантом на данный момент является библиотека pipreqs (установка «pip install pipreqs») . Чтобы сгенерировать файл requirements.txt надо в команде указать просто путь до папки с проектом, т.е. : pipreqs /path/to/project/folder . Если requirements.txt уже есть и необходимо его перезаписать, то используйте флаг —force . Если просто хотите посмотреть на используемые библиотеки без создания, флаг —print.
В конце приведу пример созданного файла:

PyMySQL==0.7.11
pandas==0.19.2
opencv_contrib_python==3.2.0.7
beautifulsoup4==4.6.0
scikit_learn==0.19.0
python_stdnum==1.6

3 способа загрузки файла на сервер с помощью curl

Продемонстрируем curl запрос на примере, с учетом следующих ограничений.
1. Файл надо загрузить методом POST
2. Необходима авторизация
3. На сервере установлен сертификат ssl

Способ 1, командная строка: Загрузка файла непосредственно через командную строку выглядит так:

curl -i -u user:password -X POST --form datafile=@/path/to/some/file.txt https://localhost:443/page --insecure

Разберем подробнее:
-X — указываем метод POST
-u — логин и пароль пользователя
—insecure — при работе по https часто приходится тестировать в тестовом окружении где не стоит проверенный сертификат. Этой опцией отказываемся от проверки.
Чтобы ещё более подробно узнать о тонкостях команды, используйте curl —help

Способ 2, PHP: Продемонстрируем как загрузить файл

// очень полезно предварительно сделать проверку на наличие библиотеки curl для php
if  (!in_array  ('curl', get_loaded_extensions())) {
    exit("CURL is NOT installed on this server");
}

        $ch = curl_init();
        //указываем url адрес на сервере
        curl_setopt($ch, CURLOPT_URL, 'https://localhost:443/page');
        // чтобы возвращало
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // указываем метод POST
        curl_setopt($ch, CURLOPT_POST, 1); 
        // этот параметр для указания логина и пароля
        curl_setopt($ch, CURLOPT_USERPWD, "login:password");
        curl_setopt($ch, CURLOPT_POSTFIELDS, [
                'some_more_data' => 'здесь можно передать дополнительные параметры, например если эмулируется отправка формы',
                'datafile' => curl_file_create('/path/to/file.txt' , mime_content_type($path_to_file), basename('/path/to/file'))
            ]
        );
        // проверка peer для ssl отключена, смотрите также CURLOPT_SSL_VERIFYHOST для полного игнорирования ssl сертификата
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
        // все опции выставлены - выполняем запрос
        $result = curl_exec($ch);
        // распечатываем ответ сервера
        var_dump($result); 
        // закрываем соединение
        curl_close($ch);

Практически всё прокомментировано в коде, однако отмечу функцию curl_file_create , один сервер постоянно ругался что файл как-то не так указан или отсутсвует. Это вылечилось добавлением мим типа, т.е. функция curl_file_create создает дополнительные заголовки для корректной отправки файла.

Способ 3, Python : Наконец дошли до python, здесь воспользуемя отличной библиотекой requests

import requests

    auth = ('user', 'password')
    data = [
        ('some_more_field', 'some_field_data')
    ]

    # curl request
    files = {'datafile': open('/path/to/file.txt', 'rb')}
    r = requests.post('https://localhost:443/page', files=files, data=data, auth=auth)
    print(r.text)

В указанном примере открываем файл в режиме бинарного чтения, и дальше сразу делаем запроc. В запросе указаны параметры авторизации, метод, страница и файл. Если файлов несколько — просто расширьте словарь files.
Всё просто, удачи с curl!

Генерация множественных числительных в согласовании с существительным на python

Суть задачи: написать функцию, на входе у которой число и существительное, на выходе сгенерированное числительное и существительное в правильном склонении.
Такая задача очень часто возникает например в финансовой сфере, так как на документах принято писать сумму помимо цифрой — ещё и прописью.

Алгоритм склонения множественно числа очень прост. Всего существует только три варианта для любого числа. Возьмём слово доллар, тогда
Вариант 1: именительный падеж, например один доллар, тридцать один доллар, много-много-один доллар. т.е. когда число оканчивается на 1
Вариант 2: Родительный падеж, например два доллара, тридцать три доллара, много-много-четыре доллара. т.е. когда число оканчивается на 2, 3 и 4
Вариант 3: Множественная форма, Родительный падеж. например пять долларово, много-много-восемь долларов. т.е. когда число оканчивается на 5, 6, 7, 8, 9, 0
Случай с нулём лучше рассмотреть отдельно в силу различных требований от того что вы действительно хотите получить.

Внимание! Для чисел оканчивающихся на 11, 12, 13, 14 есть особенность. Поэтому
основной алгоритм выбора формы существительного после числительного будет таким:
Шаг 1: Если число оканчивается на 1, но не оканчивается на 11, то вариант 1 (Именительный падеж)
Шаг 2: Если число оканчивается на 2, 3, 4, и не оканчивается на 12, 13, 14, то вариант 2 (Родительный падеж)
Шаг 3: Всё остальное — вариант 3 (Множественный родительный падеж)

Теперь вернемся к нашей изначальной задаче, ведь на входе у нас есть только одно существительное. Значит надо уметь его поставить в одну из этих форм. Воспользуемся библиотекой на python — pymorphy2 :

import pymorphy2

morph = pymorphy2.MorphAnalyzer()
word = morph.parse('доллар')[0]
v1, v2, v3 = word.inflect({'sing', 'nomn'}), word.inflect({'gent'}), word.inflect({'plur', 'gent'})

print(v1.word, v2.word, v3.word)  # доллар доллара долларов

Если кто знаком с библиотекой pymorphy2, то возможно знают, что можно напрямую воспользоваться методом make_agree_with_number . Это действительно так, и не надо воротить лишний код, но есть одно Но — библиотека не умеет генерировать сами числительные, а лишь согласовывать, ставя в нужную форму
существительное. Чтобы именно генерировать — воспользуемся библиотекой, найденной мной на github — https://github.com/seriyps/ru_number_to_text/blob/master/num2t4ru/__init__.py (ru_number_to_text-master). Отмечу, что библиотека делает даже чуть больше чем генерация целых числительных, также возможна генерация дробных числительных. И так, создадим финальную функцию, с импортом указанной библиотеки

from num2t4ru import num2text
import pymorphy2

def get_number_and_noun(numeral, noun):
    morph = pymorphy2.MorphAnalyzer()
    word = morph.parse(noun)[0]
    v1, v2, v3 = word.inflect({'sing', 'nomn'}), word.inflect({'gent'}), word.inflect({'plur', 'gent'})
    return num2text(num=numeral, main_units=((v1.word, v2.word, v3.word), 'm'))

result = get_number_and_noun(123452, 'доллар')  
print(result)  # сто двадцать три тысячи четыреста пятьдесят два доллара

В качестве практического применения сгенерированных числительных — представьте что вам надо создать много документов word, в каждый из которых требуется подставить полученные числа. Причем сгенерированные числа с согласуемым существительным можно в дальнейшем просклонять с помощью pymorphy2. (в текущем примере числительные в именительном падеже)

Кроссплатформенный способ формирования документов Word с помощью python

В данной публикации будет рассказано как сделать кроссплатформенный шаблон Microsoft Word и в дальнейшем использовать его для генерации документов на python 3.

История такова — что каждый месяц мне надо было отправлять фактически один и тот же документ, но в котором изменены несколько полей. Подправить документ — дело в общем-то не хитрое и алгоритм прост. Сначала ищем за предыдущий месяц, открываем и ждем пока word загрузится, изменяем нужные цифры и слова вручную, изменяем, закрываем и отправляем. Но вот это меня и напрягло — ведь всё можно автоматизировать и не тратить каждый раз по 5 минут, включая отправку. Кстати про отправление писем я уже писал в статье об python и outlook .

Достаточно быстро нашлась библиотека python3 docx-mailmerge . При установке не спутайте с mailmerge, они импортируются одинаково, но нет объекта MailMerge

Создаем шаблон в документе docx, обратите внимание, что документ должен быть именно docx. (Да, шаблони придется сделать на windows, но саму генерацию можно делать уже на linux.)

В то место, где надо вставить изменяемый текст кликаем курсором, после этого идем во Insert далее Quick Parts далее Field. Выскочит окно, в нем слева выбираем MergeField и в название пишем наименование изменяемого поля, например substitution_1 . Подробнее показано на рискунке
формирование word c изменяемым полем

Когда шаблон сформируете, сохраните его, например word_tpl.docx
Приступаем к кодированию, собственно минимальный код представлен ниже

from mailmerge import MailMerge

# указываем путь до шаблона
template = r"/path/to/template/word_tpl.docx"

# создаем объект и смотрим на имеющиемся поля
document = MailMerge(template)
print(document.get_merge_fields())

document.merge(
    substitution_1='Проверка генерирации документов с русским текстом',
    substitution_2='Работает'
)

document.write('generated_word_with_python.docx')

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

Создание простого плагина с ajax на wordpress

В данном посте будет пошагово описано как создать простейший плагин для wordpress с аяксом.
Собственно вся соль в ajax — так как есть пара тонких мест. Разобьем руководство на две части, в первой опишем просто создание минимального плагина, а во второй части как добавить асинхронный вызов ajax

Часть 1 — создание базового плагина

шаг 1. создать папку с названием плагина в директории wp-content/plugins , например simple-ajax
шаг 2. создать php файл в созданной директории simple-ajax.php и написать туда следующее:

/*
Plugin Name: Simple Ajax WordPress Plugin
Plugin URI: http://zabaykin.ru
Description: Visualization of assistant invoice API
Version: 1.0.0
Author: zabaykin
Author URI: http://zabaykin.ru/
*/

После этого шага уже можно идти в панели администраторов в раздел плагины и активировать плагин.
шаг 3. Создаем функцию base_plugin

function base_plugin() {
    ob_start();
    echo "< button id='ajax_button' >press for ajax< /button >";
    return ob_get_clean();
}

шаг 4. Регистрируем созданную функцию в wordpress с помощью специальной функции

add_shortcode( 'base_plugin_shortcut', 'base_plugin' );

Разумеется, название может быть абсолютно другое, суть именно в регистрации shortcode вордпреса
шаг 5. Создаем новую страницу в панели администратора и в месте где понадобится плагин — пишем прямо в тексте [base_plugin_shortcut] . После сохранения можно открыть созданную страницу и убедиться, что конопка появилась. Таким образом первая часть создания плагина завершена, далее добавляем ajax.

Часть 2 — Асинхронный вызов ajax в wordpress

шаг 1. Для аякса понадобится javascript, поэтому рядом с файлом simple-ajax.php создадим файл simple-ajax.js со следующим содержимым:

jQuery(document).ready(function ($) {
    $('#ajax_button').click(function(){
        $.ajax({
            method: "POST",
            url: simple_ajax_url_obj.ajax_url,
            dataType: "json",
            data: {
                action: 'get_ajax_response'
            }
        })
            .done(function (data) {
                console.log('YES!!')
                console.log(data);
            })
            .fail(function (data) {
                console.log('ERROR')
                console.log(data);
            });
    })
});

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

function base_plugin() {
    ob_start();
    echo "< button id='ajax_button' >press for ajax< /button >";
    
    # ajax
    wp_enqueue_script( 'simple-ajax', plugins_url( '/simple-ajax.js', __FILE__ ), array('jquery'), '1.2', true );
    wp_localize_script( 'simple-ajax', 'simple_ajax_url_obj', array( 'ajax_url' => admin_url('admin-ajax.php')) );
    return ob_get_clean();
}

Небольшое пояснение, с помощью функции wp_enqueue_script регистрируем скрипт, указываем путь до него и указываем зависимости. В нашем случае будет использоваться jquery, поэтому укажем минимальную версия 1.2 . После регистрации скрипта, необходимо создать объект javascript , в котором будет прописан URL для ajax. Это как раз делается с помощью wp_localize_script — создается объект simple_ajax_url_obj и указывается url до php скрипта. Про action расскажем чуть ниже.
шаг 3. Также обязательно понадобятся php функция — обработчик ajax

function get_ajax_response(){
    echo "ajax base plugin for wordpress works fine!"
    wp_die();
}

Обязательно заканчивайте аяксовую функцию с помощью wp_die
шаг 4. Регистрация экшена в php. Помните в javascript был указан action: ‘get_ajax_response’ ? Пришло время его объявить и связать с php функцией. Это делается с помощью следующих двух функций

add_action( 'wp_ajax_get_ajax_response', 'get_ajax_response' );
add_action( 'wp_ajax_nopriv_get_ajax_response', 'get_ajax_response' );

Если не указать wp_ajax_nopriv — то запросы смогут делать только авторизованные пользователи. Поэтому если хотим чтобы все могли делать аяксовый запрос — необходимо добавить часть с nopriv.
Стоит отметить, что практически все запросы ajax (и с фронтенда и с бекенда) идут через административную часть admin-ajax.php, поэтому если действия подразумевают администрирование — то надо чтобы wp_ajax_nopriv_(action) хук был всегду обрамлен is_admin() === true для безопасности.

Таким образом, по нажатию кнопки в консоли браузера (консоль вызываетмся кнопкой F12) будет отображено «ajax base plugin for wordpress works fine!» И данное сообщение уведомит о том, что ваш плагин с аяксом для вордпреса работает.