Atualização de plug-in: configurações de widget

9

Eu tentei fazer alguma pesquisa sobre isso, mas ainda não encontrei nada sólido. Tenho um plug-in no qual estou trabalhando e, entre a última versão e a nova, fizemos algumas atualizações no widget que alteram alguns dos nomes das configurações (no back-end) e estou tendo problemas para criar uma rotina de atualização para fazer isso.

O que eu fiz até agora que parece funcionar (principalmente) é o seguinte:

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

Na maioria dos meus testes, isso funciona bem, mas o problema é que o widget antigo não exibe mais sua saída. Somente o título do widget será exibido. Eu posso consertar isso salvando cada widget individual e, em seguida, ele funcionará bem, mas não quero que meus usuários façam isso.

Eu pensei que algo assim poderia funcionar:

$settings = $widgets->get_settings();

foreach( $settings as $s ) {

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

    $widgets->save_settings( $s );

}

Mas parece que a save_settings()chamada deve estar errada, porque isso remove completamente o widget.

Estou tendo problemas para encontrar qualquer tipo de padrão para algo assim e gostaria de ouvir quaisquer pensamentos, idéias ou links que você possa ter para fazer algo assim.

Agradecemos antecipadamente por qualquer ajuda.

EDITAR:

Na verdade, essa não é uma pergunta sobre o rastreamento de chaves de licença ou a atualização de plug-ins que não estão hospedados no repositório WP. O que é mais importante é atualizar as configurações entre a versão 2 de um plug-in quando um usuário atualiza.

Exemplo:

a versão 1.0.0 possui um campo de configuração name

Bem, na versão 1.1.0, decidimos que precisamos do nome e do sobrenome, portanto alteramos a configuração antiga first_namee adicionamos uma nova last_name.

Transferir essas opções se salvas como meta postagem para um tipo de postagem personalizado não é problema:

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

Então essa parte é fácil. O que eu estou tendo problemas com isso parece não ser fácil é fazer a mesma coisa, mas com as configurações do WIDGET.

Espero que isso esclareça qualquer confusão e ajude a facilitar a resposta.

EDIT 2:

Resultado echo '<pre>' . print_r( $widget, true ) . '</pre>';do primeiro pedaço de código acima:

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
fonte
Acabei de ver este artigo hoje no Tutsplus, nem li tudo, mas parece ser seu aliado. Criar um Tema Licença Controlada e System Update Plugin
OnethingSimple
@OnethingSimple Obrigado pela resposta, mas isso não parece exatamente o que estou procurando. Vou atualizar a pergunta para torná-la mais clara.
Nick Young
Qualquer chance de obtermos um resumo da aparência da estrutura de configurações do widget que você está lendo (mesmo que precise alterar alguns dos valores). Isso pode ajudar a dar uma idéia do que está errado. por exemplo, eco "<pre>". print_r ($ widget, verdadeiro). "</pre>";
Corsário
@Privateer Anexado à parte inferior do OP agora.
Nick Young

Respostas:

3

Eu fiz um teste rápido apenas alterando a opção e parece funcionar.

O que eu fiz é:

  1. Escreveu um widget que possui apenas 2 campos: "Título" e "Nome". Adicione várias instâncias desse widget às minhas barras laterais. Verifique se eles são mostrados corretamente no frontend.
  2. Editou a turma para usar 3 campos: "Título" e "Primeiro nome" (para substituir "Nome") e adicionou "Sobrenome".
  3. Editou a função que registra o widget 'widgets_init'para chamar uma função que atualiza as opções do widget:

    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. Escreveu uma classe simples para atualizar as opções do widget:

    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. Editei a classe do widget para salvar a opção "is_{$widget_name}_updated"dentro do update()método, dessa forma a classe atualizadora nunca será chamada para novos usuários que nunca instalaram o widget antigo

    class My_Example_Widget {
    
        ...
    
        public function update($new_instance, $old_instance) {
            ...
    
            $widget_name = 'my_example_widget';
            update_option("is_{$widget_name}_updated", 1);
        }
    }
  6. Visitei meu site e os widgets salvos com opções antigas são exibidos sem problemas usando novas opções. (É claro que "sobrenome" está sempre vazio).

Uma boa idéia pode ser substituir a "is_{$widget_name}_updated"opção, por uma opção que armazene a versão real do widget, dessa forma será útil na próxima vez que você precisar de uma atualização.

gmazzap
fonte
ASSIM, examine sua resposta sem testá-la ainda. Parece semelhante ao que eu fiz com apenas usando update_optioncorreto? Gostaria de saber agora se o gancho importa, talvez? Estou enganchando no initgancho. Existe uma enorme diferença ao adicioná-lo ao widgets_initgancho? Eu tinha certeza que eles disparavam ao mesmo tempo. Obrigado pela ajuda.
Nick Young
@NickYoung Não há diferença no gancho. Mas no seu primeiro trecho de código (semelhante ao meu) o segundo (interno) foreachestá errado.
gmazzap
Eu só tive a chance de implementar o código que você escreveu. Funciona muito bem, mas ainda estou tendo o mesmo problema que antes. Ele transfere as opções com sucesso, mas depois de executar a rotina de atualização do plug-in, o widget para de emitir seu HTML principal e mostra apenas o título do widget. Se eu for para as configurações do widget e simplesmente clicar no botão Salvar, ele aparecerá novamente. Alguma ideia?
Nick Young
Para adicionar ao meu último comentário. É como se as opções estivessem sendo atualizadas corretamente, mas a instância real não é. Isso é mesmo uma possibilidade?
Nick Young
Não desativado todo o cache. Também testado em 2 hosts diferentes com o mesmo problema.
12115 Nick Young
1

Apenas para ponderar de um ângulo diferente - em vez de atualizar automaticamente todas as configurações na atualização do plug-in, basta procurar uma configuração "antiga" e mapear para "novas" configurações on-the-fly:

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
fonte
0

Em primeiro lugar, cada instância de um widget recebe algum tipo de ID exclusivo. Eu quero dizer que se torna um prexfix para as chaves do widget.

Lembro-me de cutucá-lo há algum tempo, mas não consigo lembrar quais eram os exatos, desculpe.

Alquimista Chefe
fonte