WordPress сделал удобным размещение плагинов для широкой публики. Просто поместите ваш плагин в репозиторий плагинов WordPress, и его смогут легко найти люди из своей панели.
Вероятно, одна из лучших особенностей репозитория заключается в том, что он позволяет легко обновлять плагины внутри панели инструментов. Уведомления об обновлениях отображаются внутри панели управления, и выполнить обновление так же просто, как нажать кнопку Обновить сейчас .
Но как быть, если вы хотите разместить плагин самостоятельно? Удобная функция обновления будет недоступна, если вы разместите свой плагин вне репозитория плагинов WordPress. Ваши пользователи также не будут уведомлены о доступном обновлении.
Из этой статьи вы узнаете, что с помощью небольшого творческого кода вы можете размещать свои собственные плагины WordPress в GitHub, сохраняя при этом функцию автоматического обновления.
Зачем размещать свой плагин в GitHub?
Может быть несколько причин, по которым вы хотите разместить свой плагин вне хранилища плагинов WordPress. Одно из основных ограничений, которые дает хранилище, заключается в том, что вы обязаны лицензировать свой плагин как GPLv2 . Я не буду останавливаться на деталях лицензирования, но в двух словах это означает, что любой может поделиться вашей работой. Поэтому, если вы хотите продать свой плагин, то размещение его в частном репозитории GitHub теперь является вариантом, который вы можете рассмотреть.
Однако из-за того, как WordPress был построен, размещение вашего плагина в GitHub отключит автоматические обновления для нашего плагина. Чтобы понять, почему это так, мы должны понять, как WordPress обрабатывает обновления плагинов.
Как WordPress обновляет плагины
Во-первых, давайте рассмотрим, как WordPress выполняет обновления плагинов, чтобы лучше понять, почему плагины с самостоятельным размещением не могут иметь автоматические обновления.
WordPress периодически проверяет хранилище WordPress на наличие обновлений установленных плагинов. Он получает кучу информации о каждом плагине, такую как его последняя версия и URL пакета плагина. Это то, что мы обычно видим на странице администрирования плагина, когда получаем уведомление об обновлении:
Когда мы нажимаем ссылку View version xx details , WordPress выполняет другой поиск в репозитории плагинов. На этот раз он получает более подробную информацию о плагине, например, его описание, журнал изменений, версию WordPress, в которой он тестировался, и многое другое. Эта информация показана нам в лайтбоксе:
Наконец, при нажатии на ссылку « Обновить сейчас» обновленный пакет плагинов загружается и устанавливается.
Так почему же автоматические обновления не работают для плагинов, размещаемых самостоятельно? Это потому, что WordPress пытается найти его в хранилище плагинов WordPress и не может найти его там!
План игры
Мы планируем включить автоматическое обновление с помощью нашего плагина, размещенного на GitHub.
Вот список того, что нам нужно сделать, чтобы это работало:
- Нам нужен способ развертывания обновлений плагинов в GitHub.
- Мы должны показать уведомления об обновлении версии плагина,
- Было бы неплохо отобразить информацию о плагине при нажатии на ссылку View version xx details .
- Мы также хотим успешно установить обновление плагина, когда нажата ссылка на обновление ,
Как выполнить план
Мы будем использовать некоторые фильтры WordPress, чтобы реализовать план игры. Эти:
-
pre_set_site_transient_update_plugins.
Этот фильтр вызывается, когда WordPress пытается проверить наличие обновлений плагина. -
plugins_api.
Этот используется, когда WordPress показывает детали обновления плагина. -
upgrader_post_install.
Наконец, это вызывается после успешной установки плагина.
Мы собираемся подключиться к этим фильтрам, а затем вставить наши данные в результаты, чтобы WordPress подумал, что наш плагин находится в репозитории плагинов WordPress. Данные, которые мы добавим, будут получены из нашего репозитория GitHub и должны имитировать данные, предоставляемые хранилищем плагинов.
Настройка проекта GitHub
Прежде чем мы продолжим кодирование, давайте сначала поговорим о GitHub и о том, как мы будем использовать его для выдачи данных, которые нам нужны для подачи в WordPress.
Вам понадобится либо частный, либо публичный репозиторий GitHub . Ваше репо должно содержать все ваши файлы плагинов, а не сжатую копию вашего плагина.
Мы будем использовать классную функцию GitHub под названием Releases .
Хорошая вещь о выпусках заключается в том, что он получает текущую кодовую базу в хранилище и создает загружаемый zip-файл для каждого конкретного выпуска. Мы можем сказать WordPress загрузить этот zip-файл при обновлении нашего плагина.
Еще одна полезная вещь в Releases заключается в том, что мы можем указать детали обновления нашего плагина в заметках о выпуске. Затем мы можем проанализировать это и отобразить в лайтбоксе WordPress для подробностей обновления плагина. Мы можем пойти дальше и даже разрешить GitHub уценку для нашего журнала изменений.
Когда пришло время развернуть обновление для нашего плагина, следуйте форматированию на изображении выше, когда вы создаете новую версию:
- Имя тега: версия плагина (только номер)
- Примечания к выпуску: описание обновления
Создание нашего класса обновлений
Теперь пришло время кодировать наш плагин!
Сначала мы создаем отправную точку для нашего класса:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
class BFIGitHubPluginUpdater {
private $slug;
private $pluginData;
private $username;
private $repo;
private $pluginFile;
private $githubAPIResult;
private $accessToken;
function __construct( $pluginFile, $gitHubUsername, $gitHubProjectName, $accessToken = » ) {
add_filter( «pre_set_site_transient_update_plugins», array( $this, «setTransitent» ) );
add_filter( «plugins_api», array( $this, «setPluginInfo» ), 10, 3 );
add_filter( «upgrader_post_install», array( $this, «postInstall» ), 10, 3 );
$this->pluginFile = $pluginFile;
$this->username = $gitHubUsername;
$this->repo = $gitHubProjectName;
$this->accessToken = $accessToken;
}
// Get information regarding our plugin from WordPress
private function initPluginData() {
// code here
}
// Get information regarding our plugin from GitHub
private function getRepoReleaseInfo() {
// code here
}
// Push in plugin version information to get the update notification
public function setTransitent( $transient ) {
// code here
return $transient;
}
// Push in plugin version information to display in the details lightbox
public function setPluginInfo( $false, $action, $response ) {
// code ehre
return $response;
}
// Perform additional actions to successfully install our plugin
public function postInstall( $true, $hook_extra, $result ) {
// code here
return $result;
}
}
|
Это структура класса, которую мы собираемся использовать. Мы просто в основном определили все функции, которые мы собираемся использовать, и создали наши фильтры. Этот класс на данный момент ничего не делает, кроме как присвоить значения свойствам класса.
Аргументы конструктора
Для выполнения нашего класса нам понадобится несколько аргументов:
-
$pluginFile
: мы будем вызывать этот класс из нашего основного скрипта плагина, он должен иметь значение__FILE__
. Мы узнаем подробности о нашем плагине позже. -
$gitHubUsername
: ваше имя пользователя GitHub -
$gitHubProjectName
: имя вашего репозитория GitHub -
$accessToken
: токен доступа, который позволит нам просматривать детали частного репозитория GitHub. Если ваш проект размещен в общедоступном репозитории GitHub, просто оставьте это поле пустым.
Теперь давайте заполним функции нашего класса некоторым кодом.
Функция initPluginData
Это самая простая функция в нашем классе. Нам понадобится слаг нашего плагина и другая информация в оставшейся части скрипта, поэтому для удобства мы помещаем необходимые вызовы в функцию.
1
2
|
$this->slug = plugin_basename( $this->pluginFile );
$this->pluginData = get_plugin_data( $this->pluginFile );
|
Функция getRepoReleaseInfo
Эта функция предназначена для связи с GitHub для получения нашей информации о выпуске. Мы будем использовать GitHub API для получения подробной информации о нашем последнем выпуске. Затем сохраните все, что мы получили, в нашем githubAPIResult
для дальнейшей обработки.
Фильтр pre_set_site_transient_update_plugins
вызывается дважды в WordPress: один раз, когда он проверяет наличие обновлений для плагина, а другой — после получения результатов. Поскольку мы будем использовать эту функцию в этом фильтре, мы будем дважды запрашивать GitHub API. Нам просто нужно получить информацию от GitHub один раз:
1
2
3
4
|
// Only do this once
if ( ! empty( $this->githubAPIResult ) ) {
return;
}
|
Далее мы будем использовать GitHub API для получения информации о наших выпусках:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// Query the GitHub API
$url = «https://api.github.com/repos/{$this->username}/{$this->repo}/releases»;
// We need the access token for private repos
if ( ! empty( $this->accessToken ) ) {
$url = add_query_arg( array( «access_token» => $this->accessToken ), $url );
}
// Get the results
$this->githubAPIResult = wp_remote_retrieve_body( wp_remote_get( $url ) );
if ( ! empty( $this->githubAPIResult ) ) {
$this->githubAPIResult = @json_decode( $this->githubAPIResult );
}
|
Наконец, мы сохраним данные только для последней версии плагина:
1
2
3
4
|
// Use only the latest release
if ( is_array( $this->githubAPIResult ) ) {
$this->githubAPIResult = $this->githubAPIResult[0];
}
|
Теперь мы можем получить данные нашего плагина из GitHub. Мы будем анализировать эти данные в последующих функциях.
Функция setTransitent
Эта функция вызывается, когда WordPress проверяет обновления плагинов. Наша задача здесь — использовать данные о выпуске GitHub для предоставления информации для обновления нашего плагина.
Первое, что мы делаем, это проверяем, проверял ли WordPress уже ранее обновления плагинов. Если это так, то нам не нужно снова запускать оставшуюся функцию.
1
2
3
4
|
// If we have checked the plugin data before, don’t re-check
if ( empty( $transient->checked ) ) {
return $transient;
}
|
Далее мы получим информацию о плагине, которую будем использовать:
1
2
3
|
// Get plugin & GitHub release information
$this->initPluginData();
$this->getRepoReleaseInfo();
|
После вызова этих двух функций мы можем проверить версию нашего локального плагина из версии (имя тега), найденной в GitHub. Мы можем использовать удобную функцию PHP version_compare
для сравнения двух значений:
1
2
|
// Check the versions if we need to do an update
$doUpdate = version_compare( $this->githubAPIResult->tag_name, $transient->checked[$this->slug] );
|
Наконец, доступно обновление плагина, нам нужно предложить администратору отобразить уведомление об обновлении. Мы делаем это, заполняя переменную $transient
нашей обновленной информацией о плагине.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
// Update the transient to include our updated plugin data
if ( $doUpdate == 1 ) {
$package = $this->githubAPIResult->zipball_url;
// Include the access token for private GitHub repos
if ( !empty( $this->accessToken ) ) {
$package = add_query_arg( array( «access_token» => $this->accessToken ), $package );
}
$obj = new stdClass();
$obj->slug = $this->slug;
$obj->new_version = $this->githubAPIResult->tag_name;
$obj->url = $this->pluginData[«PluginURI»];
$obj->package = $package;
$transient->response[$this->slug] = $obj;
}
return $transient;
|
После того, как эта функция обработает нашу информацию GitHub, наш администратор сможет отображать уведомления на странице администрирования плагина:
Функция setPluginInfo
Цель этой функции — собрать сведения об обновленном плагине из заметок о выпуске. Вся эта информация будет отображаться внутри лайтбокса при нажатии на ссылку View version xx details .
Во-первых, давайте получим информацию о нашем плагине:
1
2
3
|
// Get plugin & GitHub release information
$this->initPluginData();
$this->getRepoReleaseInfo();
|
Затем мы проверяем, пришло ли время для отображения чего-либо. Мы можем проверить, пытаемся ли мы загрузить информацию для нашего текущего плагина, проверив slug
:
1
2
3
4
|
// If nothing is found, do nothing
if ( empty( $response->slug ) || $response->slug != $this->slug ) {
return false;
}
|
Чтобы отобразить информацию о плагине, нам нужно вручную добавить информацию о плагине в переменную $response
, обычно эта переменная заполняется результатами из репозитория плагинов WordPress:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
// Add our plugin information
$response->last_updated = $this->githubAPIResult->published_at;
$response->slug = $this->slug;
$response->plugin_name = $this->pluginData[«Name»];
$response->version = $this->githubAPIResult->tag_name;
$response->author = $this->pluginData[«AuthorName»];
$response->homepage = $this->pluginData[«PluginURI»];
// This is our release download zip file
$downloadLink = $this->githubAPIResult->zipball_url;
// Include the access token for private GitHub repos
if ( !empty( $this->accessToken ) ) {
$downloadLink = add_query_arg(
array( «access_token» => $this->accessToken ),
$downloadLink
);
}
$response->download_link = $downloadLink;
|
Пока что мы добавили информацию о наших плагинах, но мы еще не проанализировали наши заметки о выпуске из нашего выпуска GitHub. Давайте посмотрим, что мы имеем в наших заметках о выпуске:
В примечаниях к выпуску мы указали три детали, касающиеся нашего выпуска: наш журнал изменений, за которым следует минимально необходимая версия WordPress, а затем последняя версия WordPress, в которой тестировался плагин. Мы собираемся проанализировать этот текст и извлечь эти значения.
Поскольку мы размещаем наш плагин в GitHub, было бы неплохо, если бы у нас была возможность использовать разметку GitHub в наших заметках о выпуске. Я собираюсь использовать PHP-класс ParseDown для преобразования текста уценки в HTML:
1
2
|
// We’re going to parse the GitHub markdown release notes, include the parser
require_once( plugin_dir_path( __FILE__ ) . «Parsedown.php» );
|
Мы также собираемся создать вкладки в лайтбоксе, чтобы они соответствовали тому, как плагины, размещенные в репозитории WordPress, отображают свою информацию. Один будет для описания плагина, а другой для нашего журнала изменений:
1
2
3
4
5
6
7
|
// Create tabs in the lightbox
$response->sections = array(
‘description’ => $this->pluginData[«Description»],
‘changelog’ => class_exists( «Parsedown» )
?
: $this->githubAPIResult->body
);
|
Наконец, мы собираемся извлечь значения для потребностей и протестированы :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Gets the required version of WP if available
$matches = null;
preg_match( «/requires:\s([\d\.]+)/i», $this->githubAPIResult->body, $matches );
if ( ! empty( $matches ) ) {
if ( is_array( $matches ) ) {
if ( count( $matches ) > 1 ) {
$response->requires = $matches[1];
}
}
}
// Gets the tested version of WP if available
$matches = null;
preg_match( «/tested:\s([\d\.]+)/i», $this->githubAPIResult->body, $matches );
if ( ! empty( $matches ) ) {
if ( is_array( $matches ) ) {
if ( count( $matches ) > 1 ) {
$response->tested = $matches[1];
}
}
}
return $response;
|
Функция postInstall
В этой последней функции мы будем иметь дело с выполнением дополнительных процессов, которые нам необходимы для полной установки нашего плагина после его загрузки.
При создании релиза для нашего репозитория GitHub он автоматически создает ZIP-файл для этого конкретного релиза. Имя файла для zip-файла генерируется GitHub в формате reponame-tagname.zip . Он также содержит каталог, в котором находятся наши файлы плагинов. Аналогично, имя каталога для этого также соответствует формату reponame-tagname .
Обычно, когда WordPress загружает и распаковывает архив плагина, имя каталога плагина не меняется. Если каталог вашего плагина — my-awesome-plugin , после удаления старых файлов плагина и разархивирования обновленного, ваш каталог все равно будет называться my-awesome-plugin . Но поскольку GitHub меняет имя каталога нашего плагина каждый раз, когда мы разворачиваем релиз, WordPress не сможет найти наш плагин. Он все еще сможет установить его, но не сможет повторно активировать. Мы можем решить эту проблему, переименовав новый каталог, чтобы он соответствовал старому.
Первым делом первым:
1
2
|
// Get plugin information
$this->initPluginData();
|
Затем мы должны проверить, активирован ли наш плагин, чтобы потом его можно было активировать:
1
2
|
// Remember if our plugin was previously activated
$wasActivated = is_plugin_active( $this->slug );
|
Теперь мы переименуем наш обновленный каталог плагинов, чтобы он соответствовал старому. Мы используем функцию move
здесь, но так как мы указываем один и тот же каталог, это будет похоже на его переименование:
1
2
3
4
5
6
|
// Since we are hosted in GitHub, our plugin folder would have a dirname of
// reponame-tagname change it to our original one:
global $wp_filesystem;
$pluginFolder = WP_PLUGIN_DIR .
$wp_filesystem->move( $result[‘destination’], $pluginFolder );
$result[‘destination’] = $pluginFolder;
|
Последним шагом будет повторная активация плагина:
1
2
3
4
5
6
|
// Re-activate plugin if needed
if ( $wasActivated ) {
$activate = activate_plugin( $this->slug );
}
return $result;
|
Вызов нашего класса обновлений GitHub
Теперь, когда класс закончен, остается только вызвать его в нашем основном файле плагина:
1
2
3
4
|
require_once( ‘BFIGitHubPluginUploader.php’ );
if ( is_admin() ) {
new BFIGitHubPluginUpdater( __FILE__, ‘myGitHubUsername’, «Repo-Name» );
}
|
Пробовать
Это оно! Просто включите этот класс и вызовите его в свой плагин, и он должен начать проверять наличие обновлений автоматически.
Чтобы проверить, работает ли он, создайте новый выпуск для своего репозитория GitHub и следуйте инструкциям, изложенным ранее:
Создав релиз, вы можете принудительно заставить WordPress проверять наличие обновлений, нажав кнопку обновления в панели администратора.
Вывод
Я надеюсь, вы узнали кое-что о том, как работает WordPress и как выполняется весь процесс обновления плагинов. Вы можете скачать полный скрипт по ссылкам для скачивания вверху этой статьи.
Я надеюсь, вам понравилась эта статья. Я высоко ценю любые отзывы, комментарии и предложения. Поделитесь своими мыслями ниже!