Не повторяйте себя: автоматизация повторяющихся задач с помощью WP-CLI

Вам когда-нибудь приходилось администрирования WordPress, обновлять темы, плагины и ядро WP? Конечно, да. Вас просили: «Можете ли вы создать / обновить / удалить всех пользователей в этом CSV-файле?» Я уверен, что вы тоже столкнулись с этим. Вы пробовали мигрировать сайт и хотели, чтобы у вас был плагин или сторонний инструмент, который вы могли бы использовать для выполнения этой работы? У меня есть!

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

Что такое WP-CLI?

Если вы еще никогда не слышали о WP-CLI, вы не одиноки. Ниже приведено краткое описание, того, что такое 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 поиск и замена строк в вашей базе данных.

Полный список команд  WP-CLI, вы увидите, что имеется множество доступных команд для повторяющихся задач, которые каждый разработчик WordPress или веб-сайт поддерживает на ежедневной или еженедельной основе. Эти команды избавили меня от бесчисленных часов указания, нажатия и ожидания перезагрузки страницы в течение года.

Вы уверены? Готовы начать? Отлично!

Вам необходимо будет установить WP-CLI с вашим WordPress (или глобально на вашем локальном компьютере). Если вы еще не установили WP-CLI в локальную среду разработки, инструкции по установке WP-CLI можно найти на веб-сайте здесь. Если вы используете Varying Vagrant Vagrants (VVV2), WP-CLI включен. Многие хостинг-провайдеры также используют WP-CLI на своей платформе. Предполагаю, что вы все успешно установили.

Использование WP-CLI для решения проблемы

Чтобы решить проблему повторяющихся задач, нам нужно сделать пользовательскую команду WP-CLI доступной для нашей установки WordPress. Одним из самых простых способов добавления функциональности на любой сайт является создание плагина. Мы будем использовать плагин в этом примере по трем основным причинам:

  1. Мы можем отключить пользовательскую команду, если нам это не понадобится
  2. Мы можем легко расширять наши команды и подкоманды, сохраняя модульность.
  3. Мы можем поддерживать функциональность по темам и даже другим установкам 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' );

Этот блок кода делает для нас две вещи:

  1. Он определяет TOPTAL_WP_CLI_COMMANDS, который принимает два аргумента.
  2. Он назначает команду 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(). Если юзер с таким email не найден, выдаст предупреждение, на экране нашего терминала, что письмо не было найдено:

$ wp toptal remove_user --email=me@me.com --dry-run

Warning: The user me@me.com does not seem to exist.

Затем email сохраняется в массиве $emails_not_existing для дальнейшего отображения. Затем мы инкременитруем общее предупреждение на единицу и продолжаем цикл до следующего письма.

Если email существует, будем использовать переменные $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;
	}
	$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 is true что означает, что пользователь имеет доступ к уровню членства, мы хотим запустить функцию для удаления этого уровня. В этом примере мы будем использовать the function_to_deactivate_membership_level()для выполнения данного действия.

Однако, прежде чем мы фактически удалим уровень от пользователя, мы хотим заключить эту функцию в условную проверку, чтобы убедиться, что это фактически dry-run. Если это так, мы не хотим ничего удалять, только сообщаем, что мы это сделали. Если это не dry-run, тогда мы продолжим и удалим уровень от пользователя, запишем наше сообщение о успехе на терминал и продолжим цикл по массиву emails.

Если, с другой стороны, значение $has_level false что означает, что пользователь не имеет доступа к уровню членства, мы хотим зарегистрировать предупреждение для терминала, в $emails_without_level, и продолжим цикл по массиву emails.

Завершение и отчет

Как только цикл закончен, мы хотим записать результаты на консоль. Если это был сухой прогон, мы хотим записать дополнительное сообщение на консоль:

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 and 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=
 * : Membership level to check for and remove
 *
 * --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=me@test.com,another@email.com, and@another.com --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)

Теперь наша пользовательская команда завершена.

 

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

Иногда я обнаружил, что этот сценарий не удалит всех пользователей, которые он регистрирует, как «удаленные». Это, скорее всего, связано с тем, что скрипт работает быстрее, чем могут выполняться запросы. Ваш опыт может отличаться в зависимости от среды и настройки, в которой выполняется сценарий. Быстрый переход вокруг этого — это многократное выполнение с теми же входами; он в конечном итоге обнуляется и сообщает, что ни один пользователь не был удален.

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

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

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

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

Оригинал статьи Don’t Repeat Yourself: Automating Repetitive Tasks with WP-CLI

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *