Releasing new plugin version, how to rename old options keys?

I have everything ready for publishing a new version of my plugin but one last issue stands…

The old version had no naming convention for its key option names.

Read More

The options grew and I renamed all of them, using prefixes for the sake of good coding practice and my own sanity.

I thought of putting a warning in the Description and the Changelog, but I think it would be gentler if I could make an internal import method.

So, that’s the question:

  • how to run a function on plugin update?
  • and how to check if $myOptions[‘old_key’] exists, pass it value to $myOptions[‘new_key’] and finally delete the old_key

thanks,

Related posts

Leave a Reply

3 comments

  1. You should store a version number for your plugin in the database (if you don’t already, add this pronto), using that you can do this (note that this is pseudocode):

    if( $db_version < {your desired version} ) {
        // previous updates and such
        $db_version = $new_version; //put that in the database
    }
    if( $db_version < $current_version ) {
        create $options array
        foreach( $option as $o ) {
            if( get_option( $o['old_name'] ) ) {
                update_option( $o['new_name'], get_option( $o['old_name'] ) );
                delete_option( $o['old_name'] ); //clean up behind yourself
            }
        }
        and then update your database version again
    }
    

    Then, when you release your next update, you change $current_version to the version in which the change happened. The reason behind using this method is that if your updates are ever incrimental (which is to say, you can’t go from 1.1 to 1.9, you have to hit 1.3 and 1.5 in between or something like that), you will have a structure in place to manage that. If it gets complex, I’ll often keep the code clean and just have the if statement execute something like wpse49717_plugin_release_150() and manage the updates and such with that.

    I’d just like to note (well, really, reiterate) that you should only be using this structure for your incrimental updates. You should wholly expect this code to only be run ONCE, so make sure you’re updating your database versions and such.

  2. Here’s a nicer, more automated approach (following this answer):

    class MyPlugin{
    
      const 
        OPTION_NAME = 'my_plugin_options',
        VERSION     = '1.0';
    
      protected
        $options  = null,
    
        // default options and values go here
        $defaults = array(
                      'version'     => self::VERSION, // this one should not change
                      'test_option' => 'abc',
                      'another_one' => 420, 
                    );
    
      public function getOptions(){
    
        // already did the checks
        if(isset($this->options))
          return $this->options;    
    
        // first call, get the options
        $options = get_option(self::OPTION_NAME);
    
        // options exist
        if($options !== false){
    
          $new_version = version_compare($options['version'], self::VERSION, '!=');
          $desync = array_diff_key($this->defaults, $options) !== array_diff_key($options, $this->defaults);
    
          // update options if version changed, or we have missing/extra (out of sync) option entries 
          if($new_version || $desync){
    
            $new_options = array();
    
            // check for new options and set defaults if necessary
            foreach($this->defaults as $option => $value)
              $new_options[$option] = isset($options[$option]) ? $options[$option] : $value;        
    
            // update version info
            $new_options['version'] = self::VERSION;
    
            update_option(self::OPTION_NAME, $new_options);
            $this->options = $new_options;  
    
          // no update was required
          }else{
            $this->options = $options;     
          }
    
    
        // new install (plugin was just activated)
        }else{
          update_option(self::OPTION_NAME, $this->defaults);
          $this->options = $this->defaults; 
        }
    
        return $this->options; 
    
      }    
    
    }
    

    First call to $this->getOptions() will do all the necessary updates to your options. The only things you need to adjust are the constants / $defaults variable.

  3. Here’s the summary of how I solved the issue. The trigger for updating the options is to check if the new option “version” is present or not. And from now on, I can do a version compare if needed.

    (I’m not sure if answering my own question is the right thing to do, or if it’d be better to update the question….)

    class MyPlugin {
        var $adminOptionsName = "MyPlugin";
    
        function MyPlugin() {
        }
    
        function init() {
            $this->getAdminOptions();
        }
    
        function getAdminOptions() {
    
            // New options and values
            $theNewOptions = array(
                'option_1' => 0,
                'option_2' => '',
                'version'  => '1.0'
            );
    
            // Grab the options in the database
            $theOptions = get_option($this->adminOptionsName);
    
            // Check if options need update
            if( !isset($theOptions['version']) && !empty($theOptions) ) {
                foreach( $theOptions as $key => $value ) {
                    if( $key == 'not_needed' ) {
                        unset( $theOptions[$key] );
                    }
                    if( $key == 'old_option_1') {
                        $theOptions['option_1'] = $value;
                        unset( $theOptions[$key] );
                    }
                    // etc...
                }
            }
    
            // Proceed to the normal Options check
            if (!empty($theOptions)) {
                foreach ($theOptions as $key => $option) {
                    $theNewOptions[$key] = $option;
                }
            }
    
            update_option($this->adminOptionsName, $theNewOptions);
    
        }
    }