web-dev-qa-db-fra.com

Désinstaller, Activer, Désactiver un plugin: caractéristiques typiques et procédures

Je fais un plugin wordpress. Quelles sont les choses typiques que je devrais inclure dans la fonctionnalité de désinstallation?

Par exemple, dois-je supprimer les tables que j'ai créées dans la fonction d'installation?

Est-ce que je nettoie mes entrées d'option?

Rien d'autre?

98
redconservatory

Il y a trois différenthooks. Ils se déclenchent dans les cas suivants:

  • Désinstaller
  • Désactivation
  • Activation

Comment déclencher des fonctions en toute sécurité pendant les scénarios

Ce qui suit montre les rightfaçons de lier en toute sécurité les fonctions de rappel déclenchées lors des actions mentionnées.

Comme vous pourriez utiliser ce code dans un plugin qui utilise

  • fonctions simples,
  • une classe ou
  • une classe externe,

Je vais montrer trois démos différents plugins que vous pouvez inspecter puis, plus tard, implémenter le code dans vos propres plugins.

Remarque importante dès le départ!

Comme ce sujet est extrêmement difficile et très détaillé et comporte une douzaine de cas + Edge, cette réponse ne sera jamais parfaite. Je vais continuer à l'améliorer avec le temps, alors revenez régulièrement.

(1) Activer/Désactiver/Désinstaller des plugins.

Les rappels de configuration du plugin sont déclenchés par le noyau et vous avez pasinfluence sur la façon dont le noyau effectue cela. Voici quelques points à garder à l’esprit:

  • Jamais , jamais echo/print rien (!) Lors des rappels d'installation. Ceci conduira au message headers already sent et le noyau recommandera de désactiver et de supprimer votre plugin ... ne demandez pas: je sais ...
  • Vous ne voyezaucune sortie visuelle. Maisj'ai ajouté des instructions exit() à tous les rappels afin que vous puissiez avoir un aperçu de ce qui se passe réellement. Décommentez-les simplement pour que tout fonctionne correctement.
  • Il est extrêmement important de vérifier si __FILE__ != WP_PLUGIN_INSTALL et (si ce n’est pas le cas: abandonnez!) Pour voir s’il désinstalle réellement le plug-in. Je recommanderais simplement de déclencher des callbacks on_deactivation() lors du développement, afin de vous faire gagner du temps nécessaire pour tout récupérer. Au moins, c'est ce que je fais.
  • Je fais aussi des trucs de sécurité. Certains sont effectués par noyau également, mais bon! Mieux vaut prévenir que guérir!.
    • Tout d'abord, je refuse l'accès direct aux fichiers lorsque le coeur n'est pas chargé: defined( 'ABSPATH' ) OR exit;
    • Ensuite, je vérifie si l'utilisateur actuel est autorisé à effectuer cette tâche.
    • En dernier lieu, je vérifie le référant. Remarque: il peut y avoir des résultats inattendus avec un écran wp_die() demandant les autorisations appropriées (et si vous voulez réessayer ... ouais, bien sûr), lorsque vous recevez une erreur. Cela se produit lorsque le noyau vous redirige, définit la $GLOBALS['wp_list_table']->current_action(); actuel à error_scrape et vérifie ensuite le référent pour check_admin_referer('plugin-activation-error_' . $plugin);, où $plugin est $_REQUEST['plugin']. Ainsi, la redirection se produit à la moitié du chargement de la page et vous obtenez cette barre de défilement câblée et l'écran de la filière insight la notification/message jaune de l'administrateur. Si cela se produit: Restez calme et recherchez l'erreur avec exit() et le débogage pas à pas.

(A) Plugin des fonctions simples

N'oubliez pas que cela pourrait ne pas fonctionner si vous associez les rappels avant la définition de la fonction.

<?php
defined( 'ABSPATH' ) OR exit;
/**
 * Plugin Name: (WCM) Activate/Deactivate/Uninstall - Functions
 * Description: Example Plugin to show activation/deactivation/uninstall callbacks for plain functions.
 * Author:      Franz Josef Kaiser/wecodemore
 * Author URL:  http://unserkaiser.com
 * Plugin URL:  http://wordpress.stackexchange.com/questions/25910/uninstall-activate-deactivate-a-plugin-typical-features-how-to/25979#25979
 */

function WCM_Setup_Demo_on_activation()
{
    if ( ! current_user_can( 'activate_plugins' ) )
        return;
    $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
    check_admin_referer( "activate-plugin_{$plugin}" );

    # Uncomment the following line to see the function in action
    # exit( var_dump( $_GET ) );
}

function WCM_Setup_Demo_on_deactivation()
{
    if ( ! current_user_can( 'activate_plugins' ) )
        return;
    $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
    check_admin_referer( "deactivate-plugin_{$plugin}" );

    # Uncomment the following line to see the function in action
    # exit( var_dump( $_GET ) );
}

function WCM_Setup_Demo_on_uninstall()
{
    if ( ! current_user_can( 'activate_plugins' ) )
        return;
    check_admin_referer( 'bulk-plugins' );

    // Important: Check if the file is the one
    // that was registered during the uninstall hook.
    if ( __FILE__ != WP_UNINSTALL_PLUGIN )
        return;

    # Uncomment the following line to see the function in action
    # exit( var_dump( $_GET ) );
}

register_activation_hook(   __FILE__, 'WCM_Setup_Demo_on_activation' );
register_deactivation_hook( __FILE__, 'WCM_Setup_Demo_on_deactivation' );
register_uninstall_hook(    __FILE__, 'WCM_Setup_Demo_on_uninstall' );

(B) Une architecture de classe/POO

C'est l'exemple le plus courant dans les plugins actuels.

<?php
defined( 'ABSPATH' ) OR exit;
/**
 * Plugin Name: (WCM) Activate/Deactivate/Uninstall - CLASS
 * Description: Example Plugin to show activation/deactivation/uninstall callbacks for classes/objects.
 * Author:      Franz Josef Kaiser/wecodemore
 * Author URL:  http://unserkaiser.com
 * Plugin URL:  http://wordpress.stackexchange.com/questions/25910/uninstall-activate-deactivate-a-plugin-typical-features-how-to/25979#25979
 */


register_activation_hook(   __FILE__, array( 'WCM_Setup_Demo_Class', 'on_activation' ) );
register_deactivation_hook( __FILE__, array( 'WCM_Setup_Demo_Class', 'on_deactivation' ) );
register_uninstall_hook(    __FILE__, array( 'WCM_Setup_Demo_Class', 'on_uninstall' ) );

add_action( 'plugins_loaded', array( 'WCM_Setup_Demo_Class', 'init' ) );
class WCM_Setup_Demo_Class
{
    protected static $instance;

    public static function init()
    {
        is_null( self::$instance ) AND self::$instance = new self;
        return self::$instance;
    }

    public static function on_activation()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
        check_admin_referer( "activate-plugin_{$plugin}" );

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }

    public static function on_deactivation()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
        check_admin_referer( "deactivate-plugin_{$plugin}" );

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }

    public static function on_uninstall()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        check_admin_referer( 'bulk-plugins' );

        // Important: Check if the file is the one
        // that was registered during the uninstall hook.
        if ( __FILE__ != WP_UNINSTALL_PLUGIN )
            return;

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }

    public function __construct()
    {
        # INIT the plugin: Hook your callbacks
    }
}

(C) Une architecture de classe/OOP avec un objet de configuration externe

Ce scénario suppose que vous ayez un fichier de plug-in principal et un second fichier nommé setup.php dans un sous-répertoire du plug-in nommé inc: ~/wp-content/plugins/your_plugin/inc/setup.php. Cela fonctionnera également lorsque le dossier du plug-in se trouve en dehors de la structure de dossiers par défaut WP, ainsi que lorsque le répertoire de contenu est renommé ou dans les cas où votre fichier d'installation porte un nom différent. Seul le dossier inc doit porter le même nom et le même emplacement que le répertoire racine des plugins.

Remarque: vous pouvez simplement prendre les trois fonctions register_*_hook()* et les classes et les déposer dans votre plugin.

Le fichier de plugin principal:

<?php
defined( 'ABSPATH' ) OR exit;
/**
 * Plugin Name: (WCM) Activate/Deactivate/Uninstall - FILE/CLASS
 * Description: Example Plugin
 * Author:      Franz Josef Kaiser/wecodemore
 * Author URL:  http://unserkaiser.com
 * Plugin URL:  http://wordpress.stackexchange.com/questions/25910/uninstall-activate-deactivate-a-plugin-typical-features-how-to/25979#25979
 */


register_activation_hook(   __FILE__, array( 'WCM_Setup_Demo_File_Inc', 'on_activation' ) );
register_deactivation_hook( __FILE__, array( 'WCM_Setup_Demo_File_Inc', 'on_deactivation' ) );
register_uninstall_hook(    __FILE__, array( 'WCM_Setup_Demo_File_Inc', 'on_uninstall' ) );

add_action( 'plugins_loaded', array( 'WCM_Setup_Demo_File', 'init' ) );
class WCM_Setup_Demo_File
{
    protected static $instance;

    public static function init()
    {
        is_null( self::$instance ) AND self::$instance = new self;
        return self::$instance;
    }

    public function __construct()
    {
        add_action( current_filter(), array( $this, 'load_files' ), 30 );
    }

    public function load_files()
    {
        foreach ( glob( plugin_dir_path( __FILE__ ).'inc/*.php' ) as $file )
            include_once $file;
    }
}

Le fichier d'installation:

<?php
defined( 'ABSPATH' ) OR exit;

class WCM_Setup_Demo_File_Inc
{
    public static function on_activation()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
        check_admin_referer( "activate-plugin_{$plugin}" );

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }

    public static function on_deactivation()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        $plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
        check_admin_referer( "deactivate-plugin_{$plugin}" );

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }

    public static function on_uninstall()
    {
        if ( ! current_user_can( 'activate_plugins' ) )
            return;
        check_admin_referer( 'bulk-plugins' );

        // Important: Check if the file is the one
        // that was registered during the uninstall hook.
        if ( __FILE__ != WP_UNINSTALL_PLUGIN )
            return;

        # Uncomment the following line to see the function in action
        # exit( var_dump( $_GET ) );
    }
}

(2) Mises à jour du plugin

Si vous écrivez un plug-in qui possède sa propre table de base de données ou ses propres options, il peut arriver que vous deviez modifier ou mettre à niveau des éléments.

Malheureusement, il n’existe jusqu’à présent aucune possibilité d’exécuter quelque chose sur l’installation ou la mise à jour/mise à niveau du plugin/thème. Heureusement, il existe une solution: accrochez une fonction personnalisée à une option personnalisée (oui, c'est nul, mais cela fonctionne).

function prefix_upgrade_plugin() 
{
    $v = 'plugin_db_version';
    $update_option = null;
    // Upgrade to version 2
    if ( 2 !== get_option( $v ) ) 
    {
        if ( 2 < get_option( $v ) )
        {
            // Callback function must return true on success
            $update_option = custom_upgrade_cb_fn_v3();

            // Only update option if it was an success
            if ( $update_option )
                update_option( $v, 2 );
        }
    }

    // Upgrade to version 3, runs just after upgrade to version 2
    if ( 3 !== get_option( $v ) ) 
    {
        // re-run from beginning if previous update failed
        if ( 2 < get_option( $v ) )
            return prefix_upgrade_plugin();

        if ( 3 < get_option( $v ) )
        {
            // Callback function must return true on success
            $update_option = custom_upgrade_cb_fn_v3();

            // Only update option if it was an success
            if ( $update_option )
                update_option( $v, 3 );
        }
    }

    // Return the result from the update cb fn, so we can test for success/fail/error
    if ( $update_option )
        return $update_option;

return false;
}
add_action('admin_init', 'prefix_upgrade_plugin' );

La source

Cette fonction de mise à jour est un exemple pas très beau/bien écrit, mais comme dit: C’est un exemple et la technique fonctionne bien. Améliorera cela avec une mise à jour ultérieure.

146
kaiser

Pour tester le système actuel avec les fonctionnalités requises telles que PHP version ou les extensions installées, vous pouvez utiliser quelque chose comme ceci:

<?php  # -*- coding: utf-8 -*-
/**
 * Plugin Name: T5 Check Plugin Requirements
 * Description: Test for PHP version and installed extensions
 * Plugin URI:
 * Version:     2013.03.31
 * Author:      Thomas Scholz
 * Author URI:  http://toscho.de
 * Licence:     MIT
 * License URI: http://opensource.org/licenses/MIT
 */

/*
 * Don't start on every page, the plugin page is enough.
 */
if ( ! empty ( $GLOBALS['pagenow'] ) && 'plugins.php' === $GLOBALS['pagenow'] )
    add_action( 'admin_notices', 't5_check_admin_notices', 0 );

/**
 * Test current system for the features the plugin needs.
 *
 * @return array Errors or empty array
 */
function t5_check_plugin_requirements()
{
    $php_min_version = '5.4';
    // see http://www.php.net/manual/en/extensions.alphabetical.php
    $extensions = array (
        'iconv',
        'mbstring',
        'id3'
    );
    $errors = array ();

    $php_current_version = phpversion();

    if ( version_compare( $php_min_version, $php_current_version, '>' ) )
        $errors[] = "Your server is running PHP version $php_current_version but
            this plugin requires at least PHP $php_min_version. Please run an upgrade.";

    foreach ( $extensions as $extension )
        if ( ! extension_loaded( $extension ) )
            $errors[] = "Please install the extension $extension to run this plugin.";

    return $errors;

}

/**
 * Call t5_check_plugin_requirements() and deactivate this plugin if there are error.
 *
 * @wp-hook admin_notices
 * @return  void
 */
function t5_check_admin_notices()
{
    $errors = t5_check_plugin_requirements();

    if ( empty ( $errors ) )
        return;

    // Suppress "Plugin activated" notice.
    unset( $_GET['activate'] );

    // this plugin's name
    $name = get_file_data( __FILE__, array ( 'Plugin Name' ), 'plugin' );

    printf(
        '<div class="error"><p>%1$s</p>
        <p><i>%2$s</i> has been deactivated.</p></div>',
        join( '</p><p>', $errors ),
        $name[0]
    );
    deactivate_plugins( plugin_basename( __FILE__ ) );
}

Testez avec une vérification de PHP 5.5:

enter image description here

16
fuxia