MyBB Community Forums

Full Version: Plugin updates?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Suppose I have written a plugin that creates some tables in the database upon installation (and drops them upon uninstallation). Suppose that later I created a new version with modified structure of the tables (e.g. added some columns) and changed version number. Now I want to update the the plugin running at the forum with this new version. I can uninstall the old version and then install the new one but this way I will lose all data in the plugin's table.

Is there a way of just updating the plugin without uninstalling and installing (so that the version will change but the install and uninstall functions do not execute)? Is there something like an expected plugin function (like codename_install() is but for update, e.g. codename_update()) that would handle the update? The docs don't talk about anything like this but I imagine it is quite a common task.

Thanks for any answers and tips.
plugin should be coded in such a way that deactivating it does not affect the database settings

user is expected to deactivate the old version of plugin, add new version files & activate the plugin

replies at this topic can be of some help

* plugin basics | * database methods |
* plugin hooks
* guidance on plugins making
* plugins & hooks explained
* Plugin Authoring For Beginners
* How to make a plugin
* quick tutorial on plugins making
To anyone who has the same problem:

I have probably solved my problem. In _install() I create the setting group and a setting like this:
function plugin_install()
{
    global $db;
    
    $lang->load('plugin');

    $setting_group = array(
        'name' => 'plugin-settinggroup',
        'title' => 'plugin settings',
        'description' => 'description.',
        'disporder' => 1,
        'isdefault' => 0
    );

    $gid = $db->insert_query("settinggroups", $setting_group);

    // this allows the magic, $lang
    $db->insert_query('settings', array(
        'name' => 'plugin_version',
        'gid' => $gid,
        'title' => 'Plugin version',
        'description' => '<b>DO NOT EDIT - LOSS OF DATA</b> unless you know what are you doing.',
        'optionscode' => "select\n0=0",
        'value' => 0,
        'disporder' => 999
    ));

    rebuild_settings();
}
The _activate() function then looks like this:
function plugin_activate()
{
    global $db;

    upgrade(); // HERE the magic happens

    // create and modify templates and such stuff
}

and the main magic happens in the upgrade() function that is called from the _activate(). Here it is:
function upgrade() {
    global $db, $mybb;

    // prepare an array of functions which specify the incremental updates
    $upgrades = array(
        // the initial version of database tables and settings
        'Version 1' => function () {
            global $db, $lang;
            $lang->load('plugin');
            // create base DB tables
            $db->drop_table('table1');
            $db->drop_table('table2');
            $db->write_query('CREATE TABLE ' . $db->table_prefix . 'table1 (
                data1 INT,
                data2 INT,
                PRIMARY KEY (data1)
            )');
            $db->write_query('CREATE TABLE ' . $db->table_prefix . 'table2 (
                data1 INT,
                data2 INT,
                PRIMARY KEY (data1)
            )');

            // get setting group
            $gid = $db->fetch_field($db->simple_select('settinggroups', 'gid', "name = 'plugin-settinggroup'"), 'gid');
            
            // add settings
            $setting_array = array(
                'plugin_setting1' => array(
                    'title' => $lang->plugin_setting1_title,
                    'description' => $lang->plugin_setting1_description,
                    'optionscode' => 'groupselect',
                    'disporder' => 1
                ),
                'plugin_setting2' => array(
                    'title' => $lang->plugin_setting2_title,
                    'description' => $lang->plugin_setting2_description,
                    'optionscode' => 'groupselect',
                    'disporder' => 2
                ),
            );
        
            foreach ($setting_array as $name => $setting)
            {
                $setting['name'] = $name;
                $setting['gid'] = $gid;
        
                $db->insert_query('settings', $setting);
            }
        },
        // next version where I decided to add a table column and a setting
        'Version 2' => function () {
            global $db, $lang;
            $lang->load('plugin');
            // create base DB tables
            $db->write_query('ALTER TABLE ' . $db->table_prefix . 'table1 ADD COLUMN data3 INT NOT NULL DEFAULT 0');

            // get setting group
            $gid = $db->fetch_field($db->simple_select('settinggroups', 'gid', "name = 'plugin-settinggroup'"), 'gid');
            
            // add setting
            $setting_array = array(
                'plugin_setting3' => array(
                    'title' => $lang->plugin_setting3_title,
                    'description' => $lang->plugin_setting3_description,
                    'optionscode' => 'groupselect',
                    'disporder' => 3
                )
            );
    );

    // Now let's apply the upgrades

    // get the current version of the plugin from the setting
    $ver = $mybb->settings['plugin_version'];

    // the zero-th version is empty version, i.e. only the stuff created in the _install() function
    $optionscode = "select\n0=0 - Empty";

    // now go through those elements in the $upgrades array that are after the current version
    // the options in plugin_version are numbered from zero and the zero is an empty version
    // therefore if the version is zero, the array_slice wil start at index zero so the whole array will be processed
    // if the version was one, it means that we already are at Version 1 so the slice will start at index 1 which is Version 2
    // etc. for following versions
    $i = $ver;
    foreach (array_slice($upgrades, $ver) as $verLabel => $f) {
        call_user_func($f); // call the upgrade function
        $i += 1;
        // add its entry into the $optionscode for the plugin_version setting
        $optionscode .= "\n{$i}={$i} - {$verLabel}";
    }
    // update the plugin_version setting with the new optionscode and value that corresponds to the last option code
    $db->update_query(
        'settings',
        array(
            'optionscode' => $optionscode,
            'value' => $i,
        ),
        "name = 'ratingsystem_db_version'"
    );
    // rebuild the settings and...
    rebuild_settings();
    // ... we're done!
}

This way, whenever you update your plugin in a way that requires changing the database and/or the settings (or basically anything, e.g. stored files) and you need to keep the current state (and modify it according to the changes), instead of just rewriting anything, you add a new function to the $upgrades array, deactivate the plugin on the forum, upload new files and activate again and the change in the newly added function will happen.

Of course this does not solve anything. For example, if you want to change the way the upgrading itself is handled, you obviously cannot do it via the upgrades. You should than clearly indicate in the readme or in some release notes how to upgrade the plugin, i.e. whether it is necessary to completely uninstal and then reinstall it (loss of data), or whether deactivating, uploading new files and activating will do it (i.e. by the upgrade system), or whether just copying new files is enough and no reactivation is needed (e.g. when just a library of functions was changed).

I hope it helps.