Обновление плагина: настройки виджета

9

Я попытался провести какое-то исследование по этому вопросу, но пока не нашел ничего серьезного. У меня есть плагин, над которым я работаю, и между последней версией и новой версией мы сделали некоторые обновления в виджете, которые изменяют некоторые имена настроек (на серверной части), и у меня возникают проблемы при создании процедуры обновления для этого.

То, что я сделал до сих пор, кажется, (в основном) работает так:

$widget = get_option( 'widget_name' );

if( is_array( $widget ) && ! empty( $widget ) ) {
    foreach( $widget as $a => $b ) {
        if( ! is_array( $b ) ) {
            continue;
        } 

        foreach( $b as $k => $v ) {
            $widget[$a]['setting1'] = $widget[$a]['oldsetting1'];
            $widget[$a]['setting2'] = $widget[$a]['oldsetting2'];
        }
    }

    update_option( 'widget_name', $widget );
}

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

Я думал, что-то вроде этого может работать:

$settings = $widgets->get_settings();

foreach( $settings as $s ) {

    $s['setting1'] = $s['oldsetting1'];
    $s['setting2'] = $s['oldsetting2'];

    $widgets->save_settings( $s );

}

Но кажется, что save_settings()вызов должен быть неправильным, потому что это полностью удаляет виджет.

У меня возникают проблемы с поиском какого-либо стандарта для чего-то подобного, и я просто хотел бы услышать любые мысли, идеи или ссылки, которые вам могут понадобиться, чтобы сделать что-то подобное.

Заранее благодарю за любую помощь.

РЕДАКТИРОВАТЬ:

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

Пример:

версия 1.0.0 имеет поле настроек name

Что ж, в версии 1.1.0 мы решили, что нам нужны и имя, и фамилия, поэтому мы изменили старую настройку на, first_nameа затем добавили новую last_name.

Передача этих параметров, если они сохранены в качестве мета-записи для пользовательского типа записи, не представляет проблем:

$old_name = get_post_meta( $post->ID, 'name', true );
$first_name = update_post_meta ( $post->ID, 'first_name', true );
delete_post_meta( $post->ID, 'name' );

Так что это легко. То, что у меня есть проблемы с этим, кажется, нелегко делать то же самое, но для настроек WIDGET.

Надеюсь, это устранит любую путаницу и поможет облегчить ответ.

РЕДАКТИРОВАТЬ 2:

Результат echo '<pre>' . print_r( $widget, true ) . '</pre>';из первого куска кода выше:

Array
(
[2] => Array
    (
        [title] => Class Schedule
        [id] => 23
        [display_type] => grid
        [order] => asc
        [display_title_text] => Events on
        [paging] => 1
        [list_max_num] => 7
        [list_max_length] => days
        [list_start_offset_num] => 0
        [list_start_offset_direction] => back
        [gce_per_page_num] => 7
        [gce_events_per_page] => days
    )

[3] => Array
    (
        [title] => Examples
        [id] => 24
        [display_type] => grid
        [order] => asc
        [display_title_text] => Events on
        [paging] => 1
        [list_max_num] => 7
        [list_max_length] => days
        [list_start_offset_num] => 0
        [list_start_offset_direction] => back
        [gce_per_page_num] => 7
        [gce_events_per_page] => days
    )

[_multiwidget] => 1
)
Ник Янг
источник
Я только что видел эту статью сегодня на Tutsplus, я даже не прочитал все это, но, похоже, ваш союзник. Создайте лицензированную систему обновления тем и плагинов
OnethingSimple
@OnethingSimple Спасибо за ответ, но это не совсем похоже на то, что я собираюсь сделать. Я обновлю вопрос, чтобы сделать его более понятным.
Ник Янг
При любом случае мы можем получить дамп о том, как выглядит структура настроек виджета, с которой вы читаете (даже если вам нужно изменить некоторые значения). Это может помочь дать представление о том, что происходит не так. например, echo "<pre>". print_r ($ widget, true). "</ PRE>";
Капер
@Privateer Добавлен в нижней части ОП сейчас.
Ник Янг

Ответы:

3

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

Что я сделал, это:

  1. Написал виджет, который имеет всего 2 поля: «Заголовок» и «Имя». Добавьте несколько экземпляров этого виджета на мои боковые панели. Будьте уверены, что они отображаются правильно в веб-интерфейсе.
  2. Отредактировал класс для использования 3 полей: «Заголовок» и «Имя» (вместо «Имя») и добавил «Фамилия».
  3. Отредактировал функцию, в которой зарегистрирован виджет, 'widgets_init'для вызова функции, которая обновляет параметры виджета:

    add_action( 'widgets_init', 'my_example_widget_register' );
    
    function my_example_widget_register() {
    
      $widget_name = 'my_example_widget';  // <-- You will probably replace this
    
      $options = get_option("widget_{$widget_name}");
    
      // if the widget is not updated, run a function that updates it
      if ($options && ! get_option("is_{$widget_name}_updated")) {
          // use class below to update options
          $updater = new MyExampleWidgetUpdater($widget_name, $options);
          $updater->update();
      }
    
      register_widget('My_Example_Widget'); // <-- You will probably replace this
    }
  4. Написал простой класс для обновления параметров виджета:

    class MyExampleWidgetUpdater
    {
    
      private $name;
      private $options;
    
      public function __construct($name, $options) {
         $this->name = $name;
         $this->options = $options;
      }
    
      public function update() {
        // loop all the options
        array_walk($this->options, function(&$option, $key) {
            if (is_array($option) && is_numeric($key)) {
              $option = $this->getOption($option);
            }
        });
        // update all options in DB
        update_option("widget_{$this->name}", $this->options);
        // set the widget as updated
        update_option("is_{$this->name}_updated", 1);
      }
    
      private function getOption($options) {
        if (!isset($options['name'])) {
           return $options;
        }
        $options['first_name'] = $options['name'];
        $options['last_name'] = '';
        unset($options['name']);
        return $options;
      }
    }
  5. Я отредактировал класс виджета, чтобы сохранить параметр "is_{$widget_name}_updated"внутри update()метода, таким образом, класс обновления никогда не будет вызываться для новых пользователей, которые никогда не устанавливали старый виджет

    class My_Example_Widget {
    
        ...
    
        public function update($new_instance, $old_instance) {
            ...
    
            $widget_name = 'my_example_widget';
            update_option("is_{$widget_name}_updated", 1);
        }
    }
  6. Я посетил свой сайт, и виджеты, сохраненные со старыми параметрами, отображаются без проблем с использованием новых параметров. (Конечно, «фамилия» всегда пуста).

Хорошей идеей может быть замена этой "is_{$widget_name}_updated"опции опцией, в которой хранится актуальная версия виджета, таким образом, это будет удобно в следующий раз, когда вам понадобится обновление.

Gmazzap
источник
Так что просматривая ваш ответ, пока не проверяя его. Это похоже на то, что я сделал с использованием только update_optionправильного? Мне интересно, если крючок имеет значение, может быть? Я зацепил его за initкрючок. Есть ли огромная разница, добавив его widgets_initвместо этого на крючок? Я был почти уверен, что они стреляют одновременно. Спасибо за вашу помощь.
Ник Янг
@NickYoung Там нет разницы в крючке. Но в вашем первом фрагменте кода (который похож на мой) второй (внутренний) foreachневерен.
gmazzap
Я только что получил возможность реализовать код, который вы написали. Это прекрасно работает, но у меня все та же проблема, что и раньше. Он успешно передает параметры, но после запуска процедуры обновления для плагина виджет перестает выводить свой основной HTML и показывает только заголовок виджета. Если я зайду в настройки виджета и просто нажму кнопку «Сохранить», он снова появится. Какие-нибудь мысли?
Ник Янг
Добавить в мой последний комментарий. Это похоже на то, что параметры обновляются правильно, но фактический экземпляр - нет. Это вообще возможно?
Ник Янг
Нету отключено все кеширование. Также проверено на 2 разных хостах с одинаковой проблемой.
Ник Янг
1

Просто взвесить под другим углом - вместо того, чтобы автоматически обновлять все настройки при обновлении плагина, просто проверьте «старые» настройки и сопоставьте «новые» настройки на лету:

function widget( $args, $instance ) {
    if ( isset( $instance['old_setting'] ) )
         $instance = self::_version_compat( $instance );
}

static function _version_compat( $instance ) {
    $instance['new_setting'] = $instance['old_setting'];
    // etc.

    return $instance;
}
TheDeadMedic
источник
0

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

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

Главный алхимик
источник