Aktualizacja wtyczki: ustawienia widżetu

9

Próbowałem przeprowadzić pewne badania na ten temat, ale nie znalazłem jeszcze niczego solidnego. Mam wtyczkę, nad którą pracuję i między ostatnią wersją a nową wersją wprowadziliśmy kilka aktualizacji widżetu, które zmieniają niektóre nazwy ustawień (na backendie) i mam problem z utworzeniem procedury aktualizacji, aby to zrobić.

To, co do tej pory zrobiłem, co wydaje się (głównie) działać, to:

$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 );
}

W większości moich testów działa to dobrze, ale problem polega na tym, że stary widget nie wyświetla już swoich danych wyjściowych. Wyświetlony zostanie tylko tytuł widżetu. Mogę to naprawić, przechodząc i zapisując każdy indywidualny widżet, a następnie będzie działał dobrze, ale nie chcę, aby moi użytkownicy to robili.

Myślałem, że coś takiego może działać:

$settings = $widgets->get_settings();

foreach( $settings as $s ) {

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

    $widgets->save_settings( $s );

}

Wygląda jednak na to, że save_settings()połączenie musi być nieprawidłowe, ponieważ powoduje to całkowite usunięcie widżetu.

Mam problem ze znalezieniem jakiegokolwiek standardu dla czegoś takiego i chciałbym po prostu usłyszeć wszelkie przemyślenia, pomysły lub linki, które mogą być potrzebne do zrobienia czegoś takiego.

Z góry dziękuję za wszelką pomoc.

EDYTOWAĆ:

W rzeczywistości nie jest to pytanie o śledzenie kluczy licencyjnych lub aktualizację wtyczek, które nie są hostowane w repozytorium WP. Chodzi o to, aby zaktualizować ustawienia między 2 wersjami wtyczki podczas aktualizacji użytkownika.

Przykład:

wersja 1.0.0 ma pole ustawień name

W wersji 1.1.0 zdecydowaliśmy, że potrzebujemy zarówno imienia, jak i nazwiska, dlatego zmieniamy stare ustawienie na, first_namea następnie dodajemy nowe last_name.

Przeniesienie tych opcji, jeśli zostały zapisane jako meta post dla niestandardowego typu postu, nie stanowi problemu:

$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' );

Więc ta część jest łatwa. Problem z tym, co wydaje mi się niełatwe, to robienie tego samego, ale dla ustawień WIDGET.

Mamy nadzieję, że rozwiąże to wszelkie nieporozumienia i pomoże w łatwiejszym udzieleniu odpowiedzi.

EDYCJA 2:

Wynik echo '<pre>' . print_r( $widget, true ) . '</pre>';z pierwszego fragmentu kodu powyżej:

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
)
Nick Young
źródło
Właśnie widziałem dziś ten artykuł na Tutsplus, nawet nie przeczytałem wszystkiego, ale wydaje się, że to twój sojusznik. Utwórz motyw kontrolowany licencją i system aktualizacji wtyczek
OnethingSimple
@OnethingSimple Dziękuję za odpowiedź, ale to nie wygląda tak, jak zamierzam. Zaktualizuję pytanie, aby było bardziej jasne.
Nick Young
Przy każdej okazji możemy uzyskać zrzut struktury wyglądu widżetu, w którym czytasz (nawet jeśli musisz zmienić niektóre wartości). To może pomóc w zorientowaniu się, co się dzieje. np. echo „<pre>”. print_r ($ widget, prawda). „</pre>”;
Kaper
@Privateer Dołączono teraz na dole PO.
Nick Young,

Odpowiedzi:

3

Zrobiłem szybki test po prostu zmieniając opcję i wydaje się, że działa.

To co zrobiłem to:

  1. Napisałem widżet, który ma tylko 2 pola: „Tytuł” ​​i „Nazwa”. Dodaj kilka wystąpień tego widgetu do moich pasków bocznych. Byłem pewien, że są one poprawnie wyświetlane w interfejsie użytkownika.
  2. Zmodyfikowałem klasę, aby używała 3 pól: „Tytuł” ​​i „Imię” (w celu zastąpienia „Nazwa”) i dodałem „Nazwisko”.
  3. Zmieniono funkcję rejestrującą widget, 'widgets_init'aby wywołać funkcję aktualizującą opcje widgetu:

    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. Napisałem prostą klasę, aby zaktualizować opcje widżetu:

    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. Zedytowałem klasę widżetu, aby zapisać opcję "is_{$widget_name}_updated"wewnątrz update()metody, w ten sposób klasa aktualizacji nigdy nie będzie wywoływana dla nowych użytkowników, którzy nigdy nie zainstalowali starego widżetu

    class My_Example_Widget {
    
        ...
    
        public function update($new_instance, $old_instance) {
            ...
    
            $widget_name = 'my_example_widget';
            update_option("is_{$widget_name}_updated", 1);
        }
    }
  6. Odwiedziłem moją witrynę, a widżety zapisane przy starych opcjach są wyświetlane bez problemu przy użyciu nowych opcji. (Oczywiście „nazwisko” jest zawsze puste).

Dobrym pomysłem może być zastąpienie "is_{$widget_name}_updated"opcji opcją przechowującą aktualną wersję widżetu, w ten sposób przyda się ona następnym razem, gdy będziesz potrzebować aktualizacji.

gmazzap
źródło
TAK przeglądam odpowiedź bez testowania jej jeszcze. Wygląda podobnie do tego, co zrobiłem z użyciem update_optionpoprawnego? Zastanawiam się teraz, czy haczyk może mieć znaczenie? Zaczepiam to do inithaka. Czy istnieje ogromna różnica, dodając ją widgets_initzamiast tego do haka? Byłem całkiem pewien, że strzelają w tym samym czasie. Dzięki za pomoc.
Nick Young,
@NickYoung Nie ma różnicy w haku. Ale w twoim pierwszym fragmencie kodu (tym podobnym do mojego) drugi (wewnętrzny) foreachjest nieprawidłowy.
gmazzap
Właśnie dostałem szansę na implementację napisanego przez ciebie kodu. Działa świetnie, ale wciąż mam ten sam problem, co wcześniej. Pomyślnie przesyła opcje, ale po uruchomieniu procedury aktualizacji wtyczki widżet przestaje wyświetlać swój główny kod HTML i wyświetla tylko tytuł widżetu. Jeśli przejdę do ustawień widżetów i po prostu kliknę przycisk Zapisz, pojawi się ponownie. jakieś pomysły?
Nick Young
Aby dodać do mojego ostatniego komentarza. To tak, jakby opcje były aktualizowane poprawnie, ale rzeczywista instancja nie. Czy to w ogóle możliwość?
Nick Young
Nie, wyłączone buforowanie. Przetestowano również na 2 różnych hostach z tym samym problemem.
Nick Young
1

Aby ważyć pod innym kątem - zamiast automatycznie aktualizować wszystkie ustawienia podczas aktualizacji wtyczki, po prostu sprawdź „stare” ustawienie i mapuj na „nowe” ustawienia w locie:

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
źródło
0

Z góry mojej głowy każde wystąpienie widżetu otrzymuje jakiś unikalny identyfikator. Chcę powiedzieć, że staje się prefiksem do kluczy widgetu.

Pamiętam, że jakiś czas temu wtrąciłem się, ale nie pamiętam, jakie były dokładne, przepraszam.

Główny Alchemik
źródło