Plugin-Upgrade: Widget-Einstellungen

9

Ich habe versucht, diesbezüglich Nachforschungen anzustellen, aber noch nichts Festes gefunden. Ich habe ein Plugin, an dem ich arbeite, und zwischen der letzten Version und der neuen Version haben wir einige Aktualisierungen am Widget vorgenommen, die einige der Einstellungsnamen (im Backend) ändern, und ich habe Probleme, eine Upgrade-Routine zu erstellen, um dies zu tun.

Was ich bisher getan habe, was (meistens) zu funktionieren scheint, ist Folgendes:

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

In den meisten meiner Tests funktioniert dies in Ordnung, aber das Problem besteht darin, dass das alte Widget seine Ausgabe nicht mehr anzeigt. Es wird nur der Titel des Widgets angezeigt. Ich kann dies beheben, indem ich jedes einzelne Widget speichere. Dann funktioniert es einwandfrei, aber ich möchte meine Benutzer nicht dazu bringen, dies zu tun.

Ich dachte, so etwas könnte funktionieren:

$settings = $widgets->get_settings();

foreach( $settings as $s ) {

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

    $widgets->save_settings( $s );

}

Es scheint jedoch, dass der save_settings()Aufruf falsch sein muss, da dadurch das Widget vollständig entfernt wird.

Ich habe Probleme, einen Standard für so etwas zu finden, und möchte nur Gedanken, Ideen oder Links hören, die Sie möglicherweise benötigen, um so etwas zu tun.

Vielen Dank im Voraus für jede Hilfe.

BEARBEITEN:

Dies ist eigentlich keine Frage zum Verfolgen von Lizenzschlüsseln oder zum Aktualisieren von Plugins, die nicht auf dem WP-Repo gehostet werden. Hier geht es mehr darum, die Einstellungen zwischen zwei Versionen eines Plugins zu aktualisieren, wenn ein Benutzer ein Upgrade durchführt.

Beispiel:

Version 1.0.0 hat ein Einstellungsfeld name

Nun, in Version 1.1.0 entscheiden wir, dass wir sowohl Vor- als auch Nachnamen benötigen, also ändern wir die alte Einstellung first_nameund fügen dann eine neue Einstellung hinzu last_name.

Das Übertragen dieser Optionen, wenn sie als Post-Meta für einen benutzerdefinierten Post-Typ gespeichert sind, ist kein Problem:

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

Dieser Teil ist also einfach. Was ich damit zu tun habe, scheint nicht einfach zu sein, dasselbe zu tun, aber für WIDGET-Einstellungen.

Hoffentlich wird dies Verwirrung beseitigen und dazu beitragen, dass dies leichter zu beantworten ist.

EDIT 2:

Ergebnis des echo '<pre>' . print_r( $widget, true ) . '</pre>';ersten Codeblocks oben:

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
quelle
Ich habe diesen Artikel heute auf Tutsplus gesehen, ich habe noch nicht einmal alles gelesen, aber es scheint dein Verbündeter zu sein. Erstellen Sie ein
lizenzgesteuertes
@OnethingSimple Danke für die Antwort, aber das sieht nicht ganz so aus, wie ich es mir vorstelle. Ich werde die Frage aktualisieren, um sie klarer zu machen.
Nick Young
Bei jeder Gelegenheit erhalten wir einen Speicherauszug darüber, wie die Struktur der Widget-Einstellungen aussieht, die Sie einlesen (selbst wenn Sie einige der Werte ändern müssen). Das könnte helfen, eine Vorstellung davon zu geben, was falsch läuft. zB Echo "<pre>". print_r ($ widget, true). "</ pre>";
Privateer
@Privateer Jetzt an den unteren Rand des OP angehängt.
Nick Young

Antworten:

3

Ich habe einen kurzen Test durchgeführt, um nur die Option zu ändern, und es scheint zu funktionieren.

Was ich getan habe ist:

  1. Schrieb ein Widget mit nur 2 Feldern: "Titel" und "Name". Fügen Sie meinen Seitenleisten mehrere Instanzen dieses Widgets hinzu. Stellen Sie sicher, dass sie im Frontend korrekt angezeigt werden.
  2. Die Klasse wurde bearbeitet, um 3 Felder zu verwenden: "Titel" und "Vorname" (anstelle von "Name") und "Nachname" hinzugefügt.
  3. Die Funktion, mit der das Widget registriert wird, wurde bearbeitet 'widgets_init', um eine Funktion aufzurufen, mit der die Widget-Optionen aktualisiert werden:

    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. Schrieb eine einfache Klasse, um Widget-Optionen zu aktualisieren:

    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. Ich habe die Widget-Klasse bearbeitet, um die Option "is_{$widget_name}_updated"in der update()Methode zu speichern. Auf diese Weise wird die Updater-Klasse niemals für neue Benutzer aufgerufen, die niemals ein altes Widget installiert haben

    class My_Example_Widget {
    
        ...
    
        public function update($new_instance, $old_instance) {
            ...
    
            $widget_name = 'my_example_widget';
            update_option("is_{$widget_name}_updated", 1);
        }
    }
  6. Ich habe meine Website besucht und die mit alten Optionen gespeicherten Widgets werden ohne Probleme mit neuen Optionen angezeigt. (Natürlich ist "Nachname" immer leer).

Eine gute Idee ist es, die "is_{$widget_name}_updated"Option durch eine Option zu ersetzen, in der die aktuelle Version des Widgets gespeichert wird. Auf diese Weise ist es praktisch, wenn Sie das nächste Mal ein Update benötigen.

gmazzap
quelle
Schauen Sie sich also Ihre Antwort an, ohne sie noch zu testen. Es scheint ähnlich zu sein, was ich mit der update_optionrichtigen Verwendung gemacht habe ? Ich frage mich jetzt, ob der Haken vielleicht wichtig ist? Ich hänge es an den initHaken. Gibt es einen großen Unterschied, wenn Sie es widgets_initstattdessen zum Haken hinzufügen ? Ich war mir ziemlich sicher, dass sie gleichzeitig abfeuern. Danke für Ihre Hilfe.
Nick Young
@ NickYoung Es gibt keinen Unterschied im Haken. Aber in Ihrem ersten Code-Snippet (das ähnelt dem der Mine) ist das zweite (innere) foreachfalsch.
gmazzap
Ich habe gerade die Gelegenheit bekommen, den von Ihnen geschriebenen Code zu implementieren. Es funktioniert großartig, aber ich habe immer noch das gleiche Problem wie zuvor. Die Optionen werden erfolgreich übertragen, aber nach dem Ausführen der Upgrade-Routine für das Plugin gibt das Widget die Ausgabe des Haupt-HTML-Codes nicht mehr aus und zeigt nur den Titel des Widgets an. Wenn ich zu den Widget-Einstellungen gehe und einfach auf die Schaltfläche Speichern klicke, wird sie erneut angezeigt. Irgendwelche Gedanken?
Nick Young
Zu meinem letzten Kommentar hinzufügen. Es ist so, als würden die Optionen korrekt aktualisiert, die tatsächliche Instanz jedoch nicht. Ist das überhaupt eine Möglichkeit?
Nick Young
Nein, alle Caching deaktiviert. Auch auf 2 verschiedenen Hosts mit dem gleichen Problem getestet.
Nick Young
1

Nur um aus einem anderen Blickwinkel abzuwägen - anstatt alle Einstellungen beim Plugin-Update automatisch zu aktualisieren, suchen Sie einfach im laufenden Betrieb nach einer "alten" Einstellung und ordnen Sie sie "neuen" Einstellungen zu:

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

Jede Instanz eines Widgets erhält eine eindeutige ID. Ich möchte sagen, dass dies ein Präfix für die Schlüssel für das Widget wird.

Ich erinnere mich, dass ich vor einiger Zeit darüber gestochert habe, kann mich aber nicht erinnern, was genau das war, sorry.

Chefalchemist
quelle