Хук/Действие обновления плагина WordPress начиная с версии 3.9

20 мая 2014 г., 04:15:47
Просмотры: 24.3K
Голосов: 17

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

Начиная с последних релизов (WordPress 3.9 "Smith"), был ли добавлен хук в процесс обновления плагина? Я спрашиваю, потому что это очень базовая потребность, но я не вижу, чтобы это было добавлено в кодекс (пока). Если нет, какие общепринятые и лучшие практики используют разработчики?

РЕДАКТИРОВАНИЕ: Просто для уточнения, я говорю не об активации, а об обновлении, чтобы можно было решить вопросы, связанные с изменениями в базе данных или другими изменениями.

3
Комментарии

дубликат http://wordpress.stackexchange.com/questions/61456/run-function-on-plugin-upgrade

drzaus drzaus
9 сент. 2014 г. 12:03:09

@drzaus ответ, предоставленный там, не является хорошей практикой.

Rens Tillmann Rens Tillmann
5 авг. 2016 г. 19:32:37

@RensTillmann помимо того, что это уже устарело на 2 года, связанный вопрос/ответ содержит в основном тот же ответ, но был задан на 2 года раньше, отсюда и 'дубликат'.

drzaus drzaus
8 авг. 2016 г. 22:45:56
Все ответы на вопрос 5
6
21

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

Стандартный способ WordPress для выполнения кода при обновлении плагина описан здесь:

Правильный способ обработки пути обновления — выполнять процедуру обновления только тогда, когда это необходимо. В идеале, вы должны хранить «версию» в настройке базы данных вашего плагина, а также версию в коде. Если они не совпадают, вы запускаете процедуру обновления, а затем устанавливаете настройку базы данных равной версии в коде. Именно так многие плагины обрабатывают обновления, и так же работает ядро WordPress.

и с примером кода здесь:

function myplugin_update_db_check() {
    global $jal_db_version;
    if (get_site_option( 'jal_db_version' ) != $jal_db_version) {
        jal_install();
    }
}
add_action( 'plugins_loaded', 'myplugin_update_db_check' );
20 мая 2014 г. 04:58:08
Комментарии

Спасибо - тогда я просто воспользуюсь этим методом. WP действительно нужно добавить экшен для этого :D

user1915665 user1915665
20 мая 2014 г. 05:20:11

Технически следует использовать register_activation_hook, так как в большинстве случаев плагин деактивируется/активируется при его обновлении из админки. Хук на plugins_loaded будет выполнять проверку при каждой загрузке страницы (включая фронтенд). Были разговоры о введении register_update_hook, но это было отмечено как WONTFIX некоторое время назад. Обсуждение там полезное.

drzaus drzaus
9 сент. 2014 г. 12:10:17

Важно понимать, что массовое обновление плагинов НЕ запускает хуки активации - ДОЛЖНО, но не делает в версии 3.9.2. Под "массовым обновлением" я имею в виду обновление, выполненное со страницы обновлений в Дашборде. Индивидуальные обновления, выполненные со страницы плагина, запускают хуки нормально.

Brian C Brian C
21 сент. 2014 г. 03:26:26

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

giraff giraff
1 сент. 2015 г. 19:37:21

Дополняя комментарий @giraff, то же самое относится к людям, которые управляют своим кодом с помощью систем контроля версий, таких как SVN или Git. Из-за этого данный ответ действительно является лучшим способом обработки обновлений.

doublesharp doublesharp
10 сент. 2015 г. 19:53:03

Не уверен, что это именно то, что вы имели в виду, но если вы ищете хуки, срабатывающие до и после обновления, то обратите внимание на upgrader_pre_install и upgrader_post_install соответственно.

Eugen Mihailescu Eugen Mihailescu
16 сент. 2015 г. 09:46:18
Показать остальные 1 комментариев
4

Начиная с WordPress 3.9 вы можете использовать хук upgrader_process_complete.
Этот хук срабатывает после завершения процесса обновления (плагинов и тем).

Смотрите ссылки 1, 2, 3

Пример кода:

<?php 
/**
 * Plugin Name: Test plugin 1
 * Plugin URI: https://rundiz.com
 * Description: Очень простой плагин для тестирования. Этот плагин ничего не делает.
 * Version: 0.1.8
 * Author: Vee Winch
 * Author URI: http://rundiz.com
 * License: MIT
 * License URI: https://opensource.org/licenses/MIT
 * Text Domain: test-plugin1
 * Domain Path: 
 */


add_action('upgrader_process_complete', 'testplugin_upgrade_completed', 10, 2);
/**
 * Завершение процесса обновления.
 *
 * @see \WP_Upgrader::run() (wp-admin/includes/class-wp-upgrader.php)
 * @param \WP_Upgrader $upgrader_object
 * @param array $hook_extra
 */
function testplugin_upgrade_completed(\WP_Upgrader $upgrader_object, $hook_extra)
{
    // Получаем текущую версию плагина. ( https://wordpress.stackexchange.com/a/18270/41315 )
    if(!function_exists('get_plugin_data')){
        require_once(ABSPATH . 'wp-admin/includes/plugin.php');
    }
    // https://developer.wordpress.org/reference/functions/get_plugin_data/
    $plugin_data = get_plugin_data(__FILE__);
    $plugin_version = ($plugin_data['Version'] ?? 'unknown.version');
    unset($plugin_data);

    if (
        is_array($hook_extra) && 
        array_key_exists('action', $hook_extra) && 
        $hook_extra['action'] == 'update'
    ) {
        if (
            array_key_exists('type', $hook_extra) && 
            $hook_extra['type'] == 'plugin'
        ) {
            // Если обновлены плагины.
            $this_plugin = plugin_basename(__FILE__);
            $this_plugin_updated = false;
            if (array_key_exists('plugins', $hook_extra)) {
                // Если массовое обновление плагинов (на странице обновлений)
                foreach ($hook_extra['plugins'] as $each_plugin) {
                    if ($each_plugin === $this_plugin) {
                        $this_plugin_updated = true;
                        break;
                    }
                }// endforeach;
                unset($each_plugin);
            } elseif (array_key_exists('plugin', $hook_extra)) {
                // Если обычное обновление плагина или автоматическое.
                if ($this_plugin === $hook_extra['plugin']) {
                    $this_plugin_updated = true;
                }
            }
            if ($this_plugin_updated === true) {
                // Если этот плагин только что обновлен.
                // Выполняем ваши задачи здесь.
                // НЕ обрабатывайте ничего из новой версии кода здесь, потому что он будет работать в старой версии плагина.
                // Прочтите еще раз!! Код, выполняемый здесь, не из новой (только что обновленной) версии, а из версии до этого.
                file_put_contents(WP_CONTENT_DIR . '/test.txt', 'v'.$plugin_version."\r\n", FILE_APPEND);
                // Устанавливаем транзиент для выполнения позже.
                set_transient('testplugin_just_updated', 1);
            }
        } elseif (
            array_key_exists('type', $hook_extra) && 
            $hook_extra['type'] == 'theme'
        ) {
            // Если обновлены темы.
            // То же самое, что и с плагинами: массовое обновление тем будет указано в $hook_extra['themes'] как 'theme1', 'theme2'.
            // Обычное обновление или автоматическое будет указано в $hook_extra['theme'] как 'theme1'.
        }
    }// endif; $hook_extra
}// testplugin_upgrade_completed


add_action('plugins_loaded', 'testplugin_pluginloaded');
/**
 * Запускается один раз после загрузки плагина (при каждой загрузке страницы).
 */
function testplugin_pluginloaded()
{
    // Получаем текущую версию плагина. ( https://wordpress.stackexchange.com/a/18270/41315 )
    if(!function_exists('get_plugin_data')){
        require_once(ABSPATH . 'wp-admin/includes/plugin.php');
    }
    // https://developer.wordpress.org/reference/functions/get_plugin_data/
    $plugin_data = get_plugin_data(__FILE__);
    $plugin_version = ($plugin_data['Version'] ?? 'unknown.version');
    unset($plugin_data);

    if (get_transient('testplugin_just_updated') && current_user_can('manage_options')) {
        // Если в транзиенте отмечено, что этот плагин только что обновлен и текущий пользователь - администратор.
        // Здесь можно использовать код из новой версии.
        file_put_contents(WP_CONTENT_DIR . '/test-update-by-transient.txt', 'v'.$plugin_version."\r\n", FILE_APPEND);

        // Ваш код обновления здесь.
        
        // Удаляем транзиент после выполнения, чтобы этот код не запускался снова.
        delete_transient('testplugin_just_updated');
    }
}// testplugin_pluginloaded

Хук upgrader_process_complete будет выполняться с текущей версией кода во время обновления плагина/темы. Он не использует новую версию.

Сценарий

  1. У вас есть плагин версии 1.0
  2. Вы запускаете страницу обновления или автоматическое обновление.
  3. Ваш плагин версии 2.0 будет загружен и распакован. Будет вызван хук upgrader_process_complete.
  4. Ваш плагин версии 1.0 будет выполнен в хуке upgrader_process_complete.
  5. После завершения страница перезагружается, и вызывается хук plugins_loaded.
  6. Ваш плагин версии 2.0 выполняется в хуке plugins_loaded. (Плагин должен быть активирован.)

Это уже объяснено в коде, который я опубликовал ранее (до редактирования), но, возможно, не так ясно или трудно заметить.

Хук upgrader_process_complete создан именно для этого (см. ссылку 3). Для выполнения после завершения обновления.

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

Хук upgrader_process_complete будет работать в случаях:

  1. Обновление через страницу обновлений.
  2. Обновление через страницу плагинов или тем.
  3. Обновление через автоматическое обновление или WP Cron.

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

23 мар. 2018 г. 09:54:55
Комментарии

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

user54141 user54141
26 окт. 2021 г. 22:10:21

@user54141 Да, он использует код из предыдущей версии. Вот почему я использую set_transient(), чтобы отметить, что плагин только что обновлен, и get_transient() после хука plugins_loaded (работает при перезагрузке страницы), чтобы проверить, действительно ли произошло обновление, и затем выполнить новый код. Хук plugins_loaded сработает после перезагрузки страницы, и transient проверит, что плагин только что обновлен. Как только новый обновленный код выполнится, transient будет удален, чтобы этот код запускался только один раз после обновления плагина.

vee vee
14 февр. 2022 г. 09:46:58

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

user54141 user54141
15 февр. 2022 г. 16:19:23

@user54141 Да, код в принятом ответе очень хороший. Я согласен. Однако этот хук всё ещё полезен для тех, у кого может быть идея получше моей, чтобы использовать его при завершении обновления плагина. Именно для этого и существует хук upgrader_process_complete.

vee vee
15 февр. 2022 г. 17:28:53
3

Из обсуждения, где решили не добавлять специальный хук/функцию для обновления, следует, что «большинство людей» (по состоянию на 4 года назад) используют register_activation_hook, так как он вызывается при обновлении плагина через административную панель; большинство примеров, которые я видел с тех пор, следуют этой тенденции.

Для большинства случаев я бы не рекомендовал использовать хук через plugins_loaded, так как он будет вызываться при каждой загрузке страницы. Исключение упоминается в обсуждении: пути обновления через FTP/SVN являются «крайними случаями», поскольку WordPress не имеет механизма для определения изменений плагина, и в этом случае предыдущий ответ может быть более актуальным.

Смотрите https://gist.github.com/zaus/c08288c68b7f487193d1 для примера «простой структуры» с использованием register_activation_hook.

9 сент. 2014 г. 12:25:32
Комментарии

register_activation_hook не гарантированно срабатывает при обновлениях, см. https://make.wordpress.org/core/2010/10/27/plugin-activation-hooks-no-longer-fire-for-updates/

Flimm Flimm
15 сент. 2017 г. 13:49:59

Очень важно - НЕ используйте plugins_loaded - выполняется при каждой загрузке и может быть ресурсоемким/медленным.

random_user_name random_user_name
1 мар. 2019 г. 01:17:03

register_activation_hook больше не срабатывает при обновлениях. Это было несоответствие, которое исправили. Теперь он запускается только при активации плагина.

Использование plugins_loaded рекомендуется в кодексе. Это не медленно, потому что WordPress делает единый запрос для всех настроек сайта и кэширует его, поэтому даже если вы используете get_option() для проверки версии, сохраненной в БД, это не создает запроса к БД. Просто проверяется кэшированный запрос.

user54141 user54141
26 окт. 2021 г. 22:06:01
0

Поскольку я искал что-то связанное с этим в ноябре 2023 года, хотел бы предложить следующее: фильтр update_plugins_{$hostname} был добавлен в WordPress начиная с версии 5.8.0.

Эта функция работает только если плагин использует заголовок Update URI. Поэтому, если вы разрабатываете плагин, вы можете добавить этот заголовок в начало основного файла, указав в качестве значения URL-адрес вашего JSON-эндпоинта. Затем вам нужно подключиться к фильтру, заменив {hostname} на имя хоста этого URL. Например, предположим, что у меня есть кастомный плагин по пути /wp-content/plugins/my-custom-plugin/my-custom-plugin.php, и в начале файла у меня указано:

/**
 * Plugin Name: My Custom Plugin
 * Version: 1.0.0
 * Author: AuRise Creative
 * Update URI: https://aurisecreative.com/update-my-custom-plugin/
 */

Теперь я могу подключиться к обновлениям плагина, чтобы получать данные об обновлениях (если они есть) для этого плагина.

/**
 * Проверка обновлений плагина
 *
 * @param array|false $update Данные об обновлении плагина с актуальной информацией. По умолчанию false.
 * @param array $plugin_data Заголовки плагина.
 * @param string $plugin_file Имя файла плагина.
 * @param string $locales Установленные локали для поиска переводов.
 *
 * @return array|false Ассоциативный массив с данными об обновлении в случае успеха. Иначе false.
 */
function prefix_check_for_plugin_updates($update, $plugin_data, $plugin_file, $locales = '')
{
    // Логика проверки
    return $update;
}
add_filter('update_plugins_aurisecreative.com', 'prefix_check_for_plugin_updates', 10, 4);

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

Источники:

2 нояб. 2023 г. 19:21:41
0

Вы можете подключиться к фильтрам upgrader_pre_install и upgrader_post_install.

7 июн. 2020 г. 06:47:34