Actualización de complementos: configuración de widgets

9

He intentado investigar un poco sobre esto, pero todavía no he encontrado nada sólido. Tengo un complemento en el que estoy trabajando y, entre la última versión y la nueva versión, realizamos algunas actualizaciones al widget que cambia algunos de los nombres de configuración (en el back-end) y tengo problemas para crear una rutina de actualización para hacer esto.

Lo que he hecho hasta ahora que parece funcionar (principalmente) es esto:

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

En la mayoría de mis pruebas, esto funciona bien, pero el problema es que el widget antiguo ya no muestra su salida. Solo se mostrará el título del widget. Puedo solucionar esto yendo y guardando cada widget individual y luego funcionará bien, pero no quiero hacer que mis usuarios hagan eso.

Pensé que algo como esto podría funcionar:

$settings = $widgets->get_settings();

foreach( $settings as $s ) {

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

    $widgets->save_settings( $s );

}

Pero parece que la save_settings()llamada debe ser incorrecta porque esto elimina el widget por completo.

Tengo problemas para encontrar cualquier tipo de estándar para algo como esto y me gustaría escuchar cualquier pensamiento, idea o enlace que pueda tener para hacer algo como esto.

Gracias de antemano por cualquier ayuda.

EDITAR:

En realidad, no se trata de rastrear claves de licencia o actualizar complementos que no están alojados en el repositorio de WP. De lo que se trata más es de actualizar la configuración entre 2 versiones de un complemento cuando un usuario actualiza.

Ejemplo:

la versión 1.0.0 tiene un campo de configuración name

Bueno, en la versión 1.1.0 decidimos que necesitamos tanto el nombre como el apellido, por lo que cambiamos la configuración anterior para que sea first_namey luego agregamos una nueva configuración last_name.

Transferir estas opciones si se guarda como metadato de publicación para un tipo de publicación personalizada no es un 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' );

Entonces esa parte es fácil. Lo que tengo problemas con eso parece no ser fácil es hacer lo mismo pero con la configuración WIDGET.

Esperemos que esto aclare cualquier confusión y ayude a que esto sea más fácil de responder.

EDITAR 2:

Resultado del echo '<pre>' . print_r( $widget, true ) . '</pre>';primer fragmento de código anterior:

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
fuente
Acabo de ver este artículo hoy en Tutsplus, ni siquiera lo he leído todo, pero parece ser tu aliado. Crear un sistema de actualización de
plugins
@OnethingSimple Gracias por la respuesta, pero eso no se parece a lo que estoy buscando. Actualizaré la pregunta para que quede más clara.
Nick Young
Cualquier posibilidad de que podamos obtener un volcado de cómo se ve la estructura de configuración del widget que está leyendo (incluso si tiene que cambiar algunos de los valores). Eso podría ayudar a dar una idea de lo que va mal. por ejemplo, echo "<pre>". print_r ($ widget, verdadero). "</pre>";
Privateer
@Privateer Agregado a la parte inferior del OP ahora.
Nick Young

Respuestas:

3

Hice una prueba rápida simplemente cambiando la opción y parece funcionar.

Lo que hice es:

  1. Escribió un widget que tiene solo 2 campos: "Título" y "Nombre". Agregar varias instancias de este widget a mis barras laterales. Esté seguro de que se muestran correctamente en la interfaz.
  2. Editó la clase para usar 3 campos: "Título" y "Nombre" (para reemplazar "Nombre") y agregó "Apellido".
  3. Editó la función que registra el widget 'widgets_init'para llamar a una función que actualiza las opciones del 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. Escribió una clase simple para actualizar las opciones del 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. Edité la clase de widget para guardar la opción "is_{$widget_name}_updated"dentro del update()método, de esta manera nunca se llamará a la clase de actualización para nuevos usuarios que nunca instalaron un widget antiguo

    class My_Example_Widget {
    
        ...
    
        public function update($new_instance, $old_instance) {
            ...
    
            $widget_name = 'my_example_widget';
            update_option("is_{$widget_name}_updated", 1);
        }
    }
  6. Visité mi sitio y los widgets guardados con las opciones anteriores se muestran sin problemas con las nuevas opciones. (Por supuesto, "apellido" siempre está vacío).

Una buena idea puede ser reemplazar la "is_{$widget_name}_updated"opción, con una opción que almacene la versión real del widget, de esta manera será útil la próxima vez que necesite una actualización.

gmazzap
fuente
Así que mira tu respuesta sin probarla todavía. ¿Parece similar a lo que he hecho con solo usar update_optioncorrecto? Me pregunto ahora si el gancho es importante. Lo estoy enganchando al initgancho. ¿Hay una gran diferencia al agregarlo al widgets_initgancho? Estaba bastante seguro de que dispararon al mismo tiempo. Gracias por tu ayuda.
Nick Young
@NickYoung No hay diferencia en el gancho. Pero en su primer fragmento de código (que es similar al mío), el segundo (interno) foreachestá mal.
gmazzap
Acabo de tener la oportunidad de implementar el código que escribiste. Funciona muy bien, pero sigo teniendo el mismo problema que antes. Transfiere las opciones con éxito, pero después de ejecutar la rutina de actualización del complemento, el widget deja de generar su HTML principal y solo muestra el título del widget. Si voy a la configuración del widget y simplemente hago clic en el botón Guardar, aparece nuevamente. ¿Alguna idea?
Nick Young
Para agregar a mi último comentario. Es como si las opciones se estuvieran actualizando correctamente pero la instancia real no. ¿Es eso incluso una posibilidad?
Nick Young
No, deshabilitó todo el almacenamiento en caché. También probado en 2 hosts diferentes con el mismo problema.
Nick Young
1

Solo para evaluar desde un ángulo diferente: en lugar de actualizar automáticamente todas las configuraciones en la actualización del complemento, simplemente verifique una configuración "antigua" y asigne "nuevas" configuraciones sobre la marcha:

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

Fuera de mi cabeza, cada instancia de un widget recibe una especie de ID única. Quiero decir que se convierte en un prefijo para las teclas del widget.

Recuerdo haberme metido en esto hace algún tiempo, pero no recuerdo cuáles fueron los exactos, lo siento.

Alquimista jefe
fuente