Не повторяйтесь: автоматизация повторяющихся задач с помощью WP-CLI
Опубликовано: 2022-03-11Вы когда-нибудь заходили в админку WordPress для обновления тем, плагинов и ядра WP? Конечно, есть. Вас спрашивали: «Можете ли вы создать/обновить/удалить всех пользователей в этом CSV-файле?» Я уверен, что вы тоже столкнулись с этим. Вы пытались перенести сайт и хотели, чтобы для этой работы был доступен плагин или сторонний инструмент? Я знаю, что у меня есть!
Существует очень мощный инструмент, который поможет вам с этими и другими задачами. Прежде чем я расскажу вам об этом, я хотел бы создать небольшой анекдот.
Проблема: в недавнем проекте мне нужно было регулярно повторять несколько программных задач. В частности, одна задача заключалась в обновлении разрешений на уровне пользователя на основе свидетельства покупки или подписки на уровне членства. Если компании не удавалось найти платеж от пользователя для определенного уровня членства, она требовала, чтобы этот уровень членства был удален из пользователя. Зачем это было нужно? Возможно, участник остановил подписку, но событие не запустилось, поэтому у участника все еще есть доступ, даже если он не платит за него (угу!). Или, возможно, у кого-то было пробное предложение, но срок действия этого предложения истек, а у клиента все еще есть подписка (тоже фу!).
Решение: вместо того, чтобы заходить в панель администратора и вручную удалять сотни (возможно, тысячи) подписок, я решил воспользоваться одним из моих любимых инструментов WordPress, WP-CLI, который решил проблему несколькими нажатиями клавиш.
В этом посте я хочу познакомить вас с WP-CLI (при условии, что вы еще не близкие друзья), показать вам простую пользовательскую команду, которую я написал для этой конкретной ситуации, и дать вам некоторые идеи и ресурсы для использования WP-CLI в собственное развитие.
Что такое WP-CLI?
Если вы никогда раньше не слышали о WP-CLI, вы не одиноки. Проекту, которому уже несколько лет, казалось, какое-то время он оставался вне поля зрения WordPress. Вот краткое описание того, что такое WP-CLI и что он делает с официального сайта:
WP-CLI — это набор инструментов командной строки для управления установками WordPress. Вы можете обновлять плагины, настраивать многосайтовые установки и многое другое без использования веб-браузера.
Следующие команды демонстрируют вам мощь WP-CLI из коробки:
-
wp plugin update --allобновляет все обновляемые плагины. -
wp db exportэкспортирует дамп SQL вашей базы данных. -
wp media regenerateвосстанавливает миниатюры для вложений (например, после изменения размера в вашей теме). -
wp checksum coreпроверяет, что основные файлы WordPress не были подделаны. -
wp search-replaceищет и заменяет строки в базе данных.
Если вы изучите здесь больше команд, вы увидите, что существует множество доступных команд для повторяющихся задач, которые каждый разработчик WordPress или специалист по обслуживанию сайта выполняет ежедневно или еженедельно. Эти команды сэкономили мне бесчисленные часы наведения, нажатия и ожидания перезагрузки страницы в течение года.
Вы убеждены? Готовы начать? Здорово!
Вам нужно будет установить WP-CLI вместе с вашим WordPress (или глобально на вашем локальном компьютере). Если вы еще не установили WP-CLI в локальной среде разработки, инструкции по установке можно найти на веб-сайте здесь. Если вы используете Varying Vagrant Vagrants (VVV2), включен WP-CLI. Многие хостинг-провайдеры также включают WP-CLI на свою платформу. Я предполагаю, что вы успешно установили это в будущем.
Использование WP-CLI для решения проблемы
Чтобы решить проблему повторяющихся задач, нам нужно сделать пользовательскую команду WP-CLI доступной для нашей установки WordPress. Один из самых простых способов добавить функциональности любому сайту — создать плагин. Мы будем использовать плагин в этом случае по трем основным причинам:
- Мы сможем отключить пользовательскую команду, если она нам не нужна
- Мы можем легко расширять наши команды и подкоманды, сохраняя при этом модульность.
- Мы можем поддерживать функциональность в разных темах и даже в других установках WordPress.
Создание плагина
Чтобы создать плагин, нам нужно добавить каталог в наш каталог /plugins в нашем каталоге wp-content . Мы можем назвать этот каталог toptal-wpcli . Затем создайте два файла в этом каталоге:
-
index.php, в котором должна быть только одна строка кода:<?php // Silence is golden. -
plugin.php, в который будет помещен наш код (Вы можете назвать этот файл как хотите.)
Откройте файл plugin.php и добавьте следующий код:
<?php /** * Plugin Name: TOPTAL WP-CLI Commands * Version: 0.1 * Plugin URI: https://n8finch.com/ * Description: Some rando wp-cli commands to make life easier... * Author: Nate Finch * Author URI: https://n8finch.com/ * Text Domain: toptal-wpcli * Domain Path: /languages/ * License: GPL v3 */ /** * NOTE: THIS PLUGIN FILE WILL NOT WORK IN PRODUCTION AS IS AND IS ONLY FOR DEMONSTRATION PURPOSES! * You can of course take the code and repurpose it:-). */ if ( !defined( 'WP_CLI' ) && WP_CLI ) { //Then we don't want to load the plugin return; }Эти первые несколько строк состоят из двух частей.
Во-первых, у нас есть заголовок плагина. Эта информация загружается на страницу администрирования плагинов WordPress и позволяет нам зарегистрировать наш плагин и активировать его. Требуется только имя плагина, но мы должны включить остальные для всех, кто может захотеть использовать этот код (а также для себя в будущем!).
Во-вторых, мы хотим проверить, определен ли WP-CLI. То есть мы проверяем, присутствует ли константа WP-CLI. Если это не так, мы хотим выйти из игры и не запускать плагин. Если он присутствует, мы можем запустить остальную часть нашего кода.
Между этими двумя разделами я добавил примечание о том, что этот код не следует использовать «как есть» в производстве, поскольку некоторые функции являются заполнителями для реальных функций. Если вы измените эти функции-заполнители на настоящие активные функции, не стесняйтесь удалять это примечание.
Добавление пользовательской команды
Далее мы хотим включить следующий код:
class TOPTAL_WP_CLI_COMMANDS extends WP_CLI_Command { function remove_user() { echo "\n\n hello world \n\n"; } } WP_CLI::add_command( 'toptal', 'TOPTAL_WP_CLI_COMMANDS' );Этот блок кода делает для нас две вещи:
- Он определяет класс
TOPTAL_WP_CLI_COMMANDS, в который мы можем передавать аргументы. - Он присваивает классу команду
toptal, поэтому мы можем запускать ее из командной строки.
Теперь, если мы выполним wp toptal remove_user , мы увидим:
$ wp toptal hello hello world Это означает, что наша команда toptal зарегистрирована и наша подкоманда remove_user работает.
Настройка переменных
Поскольку мы массово удаляем пользователей, мы хотим настроить следующие переменные:
// Keep a tally of warnings and loops $total_warnings = 0; $total_users_removed = 0; // If it's a dry run, add this to the end of the success message $dry_suffix = ''; // Keep a list of emails for users we may want to double check $emails_not_existing = array(); $emails_without_level = array(); // Get the args $dry_run = $assoc_args['dry-run']; $level = $assoc_args['level']; $emails = explode( ',', $assoc_args['email'] );Назначение каждой из переменных следующее:
-
total_warnings: мы подсчитаем предупреждение, если электронная почта не существует или если электронная почта не связана с уровнем членства, который мы удаляем. -
$total_users_removed: мы хотим подсчитать количество пользователей, удаленных в процессе (см. предостережение ниже). -
$dry_suffix: Если это пробный прогон, мы хотим добавить формулировку к окончательному уведомлению об успехе. -
$emails_not_existing: Хранит список писем, которые не существуют. -
$emails_without_level: Хранит список электронных писем, которые не имеют указанного уровня. -
$dry_run: логическое значение, в котором хранится, выполняет ли скрипт пробный прогон (true) или нет (false). -
$level: Целое число, представляющее уровень для проверки и, возможно, удаления. -
$email: Массив электронных писем для проверки на заданный уровень. Мы будем перебирать этот массив
С нашими установленными переменными мы готовы фактически запустить функцию. В истинном стиле WordPress мы запустим цикл.
Написание самой функции
Начнем с создания цикла foreach для циклического перебора всех писем в нашем массиве $emails :
// Loop through emails foreach ( $emails as $email ) { // code coming soon } // end foreachЗатем добавляем условную проверку:
// Loop through emails foreach ( $emails as $email ) { //Get User ID $user_id = email_exists($email); if( !$user_id ) { WP_CLI::warning( "The user {$email} does not seem to exist." ); array_push( $emails_not_existing, $email ); $total_warnings++; continue; } } // end foreach Эта проверка гарантирует, что у нас есть зарегистрированный пользователь с электронной почтой, которую мы проверяем. Он использует email_exists() , чтобы проверить, есть ли пользователь с этим адресом электронной почты. Если он не находит пользователя с этим электронным письмом, он выдает предупреждение, чтобы мы знали на экране нашего терминала, что электронное письмо не было найдено:
$ wp toptal remove_user [email protected] --dry-run Warning: The user [email protected] does not seem to exist. Затем электронное письмо сохраняется в массиве $emails_not_existing для последующего отображения. Затем мы увеличиваем общее количество предупреждений на единицу и продолжаем цикл до следующего письма.
Если электронная почта существует, мы будем использовать $user_id и $level , чтобы проверить, есть ли у пользователя доступ к уровню. Сохраняем полученное логическое значение в переменной $has_level :

// Loop through emails foreach ( $emails as $email ) { //Get User ID $user_id = email_exists($email); if( !$user_id ) { WP_CLI::warning( "The user {$email} does not seem to exist." ); array_push( $emails_not_existing, $email ); $total_warnings++; continue; } // Check membership level. This is a made up function, but you could write one or your membership plugin probably has one. $has_level = function_to_check_membership_level( $level, $user_id ); } // end foreach Как и большинство функций в этом примере, эта function_to_check_membership_level() сфабрикована, но большинство подключаемых модулей членства должны иметь вспомогательные функции для получения этой информации.
Теперь перейдем к основному действию: снятию уровня с пользователя. Мы будем использовать структуру if/else , которая выглядит так:
foreach ( $emails as $email ) { // Previous code here... // Check membership level. This is a made up function, but you could write one or your membership plugin probably has one. $has_level = function_to_check_membership_level( $level, $user_id ); if ( $has_level ) { if ( !$dry_run ) { // Deactivate membership level. This is a made up function, but you could write one or your membership plugin probably has one. function_to_deactivate_membership_level( $level, $user_id, 'inactive' ); } WP_CLI::success( "Membership canceled for {$email}, Level {$level} removed" . PHP_EOL ); $total_users_removed++; } else { WP_CLI::warning( "The user {$email} does not have Level = {$level} membership." ); array_push( $emails_without_level, $email ); $total_warnings++; } // We could echo something here to show that things are processing... } // end foreach Если значение $has_level «правдиво», что означает, что пользователь имеет доступ к уровню членства, мы хотим запустить функцию для удаления этого уровня. В этом примере мы будем использовать function_to_deactivate_membership_level() для выполнения этого действия.
Однако, прежде чем мы на самом деле удалим уровень от пользователя, мы хотим заключить эту функцию в условную проверку, чтобы увидеть, действительно ли это dry-run . Если это так, мы не хотим ничего удалять, только сообщаем, что мы это сделали. Если это не dry-run , то мы продолжим и удалим уровень у пользователя, зарегистрируем наше сообщение об успехе в терминале и продолжим просмотр писем.
Если, с другой стороны, значение $has_level равно «falsey», что означает, что у пользователя нет доступа к уровню членства, мы хотим записать предупреждение на терминал, поместить электронное письмо в массив $emails_without_level и продолжить. просматривая электронные письма.
Завершение и отчетность
После завершения цикла мы хотим вывести наши результаты на консоль. Если это был пробный запуск, мы хотим вывести в консоль дополнительное сообщение:
if ( $dry_run ) { $dry_suffix = 'BUT, nothing really changed because this was a dry run:-).'; } Этот $dry-suffix будет добавлен к предупреждениям и уведомлениям об успешном выполнении, которые мы регистрируем дальше.
В завершение мы хотим зарегистрировать наши результаты как сообщение об успешном выполнении, а наши предупреждения — как предупредительные сообщения. Мы сделаем это так:
WP_CLI::success( "{$total_users_removed} User/s been removed, with {$total_warnings} warnings. {$dry_suffix}" ); if ( $total_warnings ) { $emails_not_existing = implode(',', $emails_not_existing); $emails_without_level = implode(',', $emails_without_level); WP_CLI::warning( "These are the emails to double check and make sure things are on the up and up:" . PHP_EOL . "Non-existent emails: " . $emails_not_existing . PHP_EOL . "Emails without the associated level: " . $emails_without_level . PHP_EOL ); } Обратите внимание, что мы используем вспомогательные методы WP_CLI::success и WP_CLI::warning . Они предоставляются WP-CLI для записи информации в консоль. Вы можете легко регистрировать строки, что мы здесь и делаем, включая наши $total_users_removed , $total_warnings и $dry_suffix .
Наконец, если мы получили какие-либо предупреждения во время выполнения скрипта, мы хотим вывести эту информацию на консоль. После запуска условной проверки мы конвертируем переменные массива $emails_not_existing и $emails_without_level в строковые переменные. Мы делаем это, чтобы вывести их на консоль с помощью вспомогательного метода WP_CLI::warning .
Добавление описания
Мы все знаем, что комментарии полезны для других и для нас самих в будущем, когда мы возвращаемся к нашему коду через недели, месяцы или даже годы. WP-CLI предоставляет интерфейс кратких описаний (shortdesc) и длинных описаний (longdesc), который позволяет нам аннотировать нашу команду. Мы поместим в начало нашей команды после того, как будет определен класс TOPTAL_WP_CLI_COMMANDS :
/** * Remove a membership level from a user * * ## OPTIONS * --level=<number> * : Membership level to check for and remove * * --email=<email> * : Email of user to check against * * [--dry-run] * : Run the entire search/replace operation and show report, but don't save changes to the database. * * ## EXAMPLES * * wp toptal remove_user --level=5 [email protected],[email protected], [email protected] --dry-run * * @when after_wp_load */ В longdesc мы определяем, что мы ожидаем получить от нашей пользовательской команды. Синтаксис для shortdesc и longdesc — Markdown Extra. В разделе ## OPTIONS мы определяем аргументы, которые ожидаем получить. Если аргумент требуется, мы заключаем его в < > , а если он необязателен, мы заключаем его в [ ] .
Эти параметры проверяются при выполнении команды; например, если мы опустим обязательный параметр электронной почты, мы получим следующую ошибку:
$ wp toptal remove_user --level=5 --dry-run Error: Parameter errors: missing --email parameter (Email of user to check against) Раздел ## EXAMPLES включает пример того, как команда может выглядеть при вызове.
Наша пользовательская команда завершена. Вы можете увидеть окончательную суть здесь.
Предостережение и возможности для улучшения
Важно проанализировать работу, которую мы здесь проделали, чтобы понять, как можно улучшить, расширить и реорганизовать код. Есть много областей улучшения для этого скрипта. Вот некоторые замечания об улучшениях, которые можно было бы сделать.
Иногда я обнаруживал, что этот скрипт не удаляет всех пользователей, которых он регистрирует как «удаленные». Скорее всего, это связано с тем, что скрипт работает быстрее, чем могут выполняться запросы. Ваш опыт может различаться в зависимости от среды и настроек, в которых запускается сценарий. Быстрый способ обойти это — многократно запускать одни и те же входные данные; в конечном итоге он обнулится и сообщит, что ни один пользователь не был удален.
Сценарий можно улучшить, чтобы он ждал и подтверждал, что пользователь был удален, прежде чем регистрировать пользователя как действительно удаленного. Это замедлило бы выполнение скрипта, но было бы более точным, и вам нужно было бы запустить его только один раз.
Точно так же, если бы были обнаружены подобные ошибки, сценарий мог бы выдать ошибки, чтобы предупредить, что уровень не был удален из пользователя.
Еще одна область для улучшения скрипта — разрешить одновременное удаление нескольких уровней с одного адреса электронной почты. Сценарий может автоматически определять наличие одного или нескольких уровней и одного или нескольких электронных писем для удаления. Мне давали CSV-файлы по уровням, поэтому мне нужно было запускать только один уровень за раз.
Мы также могли бы реорганизовать часть кода, чтобы использовать тернарные операторы вместо более подробных условных проверок, которые у нас есть в настоящее время. Я решил упростить чтение для демонстрации, но не стесняйтесь делать код самостоятельно.
На последнем этапе вместо того, чтобы печатать электронные письма на консоли на последнем этапе, мы также можем автоматически экспортировать их в CSV или обычный текстовый файл.
Наконец, нет никаких проверок, чтобы убедиться, что мы получаем целое число для переменной $level или адрес электронной почты или список адресов электронной почты, разделенных запятыми, в переменной $emails . В настоящее время, если бы кто-то включил строки вместо целых чисел или имена пользователей вместо адресов электронной почты, скрипт не работал бы (и не выдавал ошибок). Могут быть добавлены проверки целых чисел и адресов электронной почты.
Идеи для дальнейшей автоматизации и дополнительного чтения
Как видите, даже в этом конкретном случае использования WP-CLI достаточно гибок и мощен, чтобы помочь вам выполнять свою работу быстро и эффективно. Вы можете задаться вопросом: «Как я могу начать внедрять WP-CLI в свой ежедневный и еженедельный процесс разработки?»
Существует несколько способов использования WP-CLI. Вот некоторые из моих любимых:
- Обновляйте темы, плагины и ядро WP, не заходя в панель администратора.
- Экспортируйте базы данных для резервного копирования или выполните быстрый дамп SQL, если я хочу протестировать SQL-запрос.
- Перенос сайтов WordPress.
- Установите новые сайты WordPress с фиктивными данными или пользовательскими настройками набора плагинов.
- Запустите контрольные суммы для основных файлов, чтобы убедиться, что они не были скомпрометированы. (На самом деле в настоящее время ведется проект по расширению этого до тем и плагинов в репозитории WP.)
- Напишите свой собственный скрипт для проверки, обновления и обслуживания хостов сайта (о чем я писал здесь).
Возможности WP-CLI почти безграничны. Вот несколько ресурсов, которые помогут вам двигаться вперед:
- Основной сайт WP-CLI: http://wp-cli.org
- Команды WP-CLI: https://developer.wordpress.org/cli/commands/
- Официальный блог WP-CLI: https://make.wordpress.org/cli/
- Справочник по WP-CLI: https://make.wordpress.org/cli/handbook/
- В WooCommerce? Проверьте WC-CLI: https://github.com/woocommerce/woocommerce/wiki/WC-CLI-Overview#woocommerce-commands.
- Подкаст-интервью с Дэниелом Баххубером, сопровождающим проекта: https://howibuilt.it/episode-28-daniel-bachhuber-wp-cli/
