插件升级:小部件设置

时间:2015-02-08 作者:Nick Young

我试着对此做了一些研究,但还没有发现任何可靠的东西。我有一个插件,在上一个版本和新版本之间,我们对小部件进行了一些更新,更改了一些设置名称(在后端),但我在创建升级例程时遇到了问题。

到目前为止,我所做的(主要)工作是:

$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 repo上托管的插件的问题。更重要的是,当用户升级时,在插件的两个版本之间更新设置。

示例:

版本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\' );
所以这部分很简单。我遇到的问题似乎并不容易,就是要做同样的事情,但要做的是小部件设置。

希望这将消除任何困惑,并有助于使这更容易回答。

编辑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
)

4 个回复
最合适的回答,由SO网友:gmazzap 整理而成

我做了一个快速测试,只是改变了选项,它似乎奏效了。

我所做的是:

编写了一个小部件,它只有两个字段:“Title”和“Name”。将此小部件的多个实例添加到我的侧栏。确保它们在前端显示正确\'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
}
编写了一个简单的类来更新小部件选项:

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;
  }
}
我编辑了widget类以保存选项"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);
    }
}
我访问了我的网站,使用旧选项保存的小部件使用新选项显示,没有问题。(当然,“姓氏”始终为空)。

一个好主意是更换"is_{$widget_name}_updated" 选项,该选项存储小部件的实际版本,这样下次需要更新时就很方便了。

SO网友:TheDeadMedic

只是想从不同的角度衡量一下,而不是在插件更新中自动升级所有设置,只需检查“旧”设置&;动态映射到“新”设置:

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

SO网友:Fernando

我在插件方面也遇到了同样的问题(升级时如何更新旧实例中的小部件选项),我解决了以下问题:

第1步:检查插件升级

您可以使用upgrader_process_complete 钩子,但它只在WordPress自动更新时触发,如果您手动上传插件,则不会触发。您可以在下面的代码参考中看到此挂钩的示例developer.wordpress.org.

所以,我用版本控制完成了:1。-定义新/当前版本的常量,以及2。-将此值保存在wp_options 一旦我们完成了更新过程。

示例:if ( $saved_version != CURRENT_VERSION ) $needs_update = true;

您还可以使用version_compare() php函数。

第2步:更新选项

在中创建新方法WP_Widget 类并从构造函数调用它,例如$this->mywidget_check_version().

此方法检查是否有版本更改(如步骤1所述),并可以使用访问所有小部件实例$this->get_settings().

使用foreach() 您只需读取每个实例并更新所需的键和值。您只需要维护实例id。例如,您可以创建一个新数组来添加和删除新/旧键和值:

$new_instances[$id][$key] = isset( $old_instances[$id][$key] ? $old_instances[$id][$key] : $default_value[$key];
完成后,使用$this更新->;保存\\u设置($new\\u实例)并在wp\\u选项中更新版本密钥。

使用这些WP_Widget 方法而不是get_option()/update_option(), 确保完整性和兼容性。WP_Widget 定义wp_options 键,实例ID并添加键$settings[\'_multiwidget\'] = 1.

当做

费尔南多。

SO网友:Chief Alchemist

在我的脑海中,小部件的每个实例都被赋予了某种唯一的ID。我想说的是,这将成为小部件键的prexfix。

我记得前一段时间戳过这个,但不记得是什么,抱歉。

结束

相关推荐

WordPress plugin DB upgrade

我在写插件。我在数据库中添加了1个自定义表。假设我的插件的当前版本是1.0,几天后我正在升级插件,现在它的版本是1.2。一段时间后的版本相同,现在的版本是1.3和。。。。。1.4现在,对于插件版本的每个版本,我都对数据库进行了一些更改。如何升级数据库。我知道选项表中的存储db版本。但我不知道,因为一些用户从1.1->1.2更新了他的插件,另一个是从1.1->1.4更新的。。。。。。。。。有些是1.2->1.4。。等只有这样才能将所有条件添加到代码中,或者任何其他解决方案都可用?????