Desinstalar, activar, desactivar un complemento: características típicas y procedimientos

91

Estoy haciendo un plugin para wordpress. ¿Cuáles son las cosas típicas que debería incluir en la función de desinstalación?

Por ejemplo, ¿debo eliminar las tablas que creé en la función de instalación?

¿Limpio las entradas de mis opciones?

¿Algo más?

    
pregunta redconservatory 15.08.2011 - 01:21

2 respuestas

139

Hay tres diferentes ganchos. Se disparan en los siguientes casos:

  • Desinstalar
  • Desactivación
  • Activación

Cómo activar funciones de forma segura durante los escenarios

A continuación se muestran las formas correctas de enganchar de forma segura las funciones de devolución de llamada que se activan durante las acciones mencionadas.

Como podría usar este código en un complemento que usa

  • funciones simples,
  • una clase o
  • una clase externa,

Mostraré tres complementos de demostración que puede inspeccionar y luego implementar el código en sus propios complementos.

Nota importante por adelantado!

Como este tema es extremadamente difícil y muy detallado y tiene más de una docena de casos, esta respuesta nunca será perfecta. Seguiré mejorándolo con el tiempo, así que vuelva a consultar periódicamente.

(1) Activar / Desactivar / Desinstalar complementos.

Las devoluciones de llamada de configuración del complemento son activadas por el núcleo y usted tiene no influencia en cómo el núcleo hace esto. Hay algunas cosas a tener en cuenta:

  • Nunca , siempre echo/print nada (!) durante la configuración de devoluciones de llamada. Esto llevará a headers already sent message y Core recomendará desactivar y eliminar su complemento ... no pregunte: lo sé ...
  • No verás ningún resultado visual. Pero agregué exit() sentencias a todas las diferentes devoluciones de llamada para que pueda obtener información sobre lo que realmente está sucediendo. Simplemente descoméntalos para ver cómo funcionan las cosas.
  • Es extremadamente importante que verifique si __FILE__ != WP_PLUGIN_INSTALL y (si no: ¡abortar!) para ver si realmente está desinstalando el complemento. Recomiendo simplemente activar on_deactivation() devoluciones de llamada durante el desarrollo, para que ahorre el tiempo que necesitaría para que todo vuelva a aparecer. Al menos, esto es lo que hago.
  • Yo también hago cosas de seguridad. Algunos se hacen por núcleo también, pero ¡hey! ¡Más vale prevenir que lamentar! .
    • Primero, rechazo el acceso directo a archivos cuando el núcleo no está cargado: defined( 'ABSPATH' ) OR exit;
    • Luego verifico si el usuario actual tiene permiso para realizar esta tarea.
    • Como última tarea, verifico el referente. Nota: Puede haber resultados inesperados con la pantalla wp_die() solicitando los permisos adecuados (y si desea intentarlo de nuevo ... sí, claro ), cuando recibió un error. Esto sucede a medida que el núcleo lo redirige, establece el $GLOBALS['wp_list_table']->current_action(); actual en error_scrape y luego verifica la referencia para check_admin_referer('plugin-activation-error_' . $plugin); , donde $plugin es $_REQUEST['plugin'] . Por lo tanto, la redirección se realiza con la mitad de la carga de la página y obtiene esta barra de desplazamiento cableada y la información de la pantalla del troquel en el cuadro amarillo de aviso / mensaje de administración. Si esto sucede: mantén la calma y busca el error con algunos exit() y depuración paso a paso.

(A) Complemento de funciones simples

Recuerde que esto podría no funcionar si enlaza las devoluciones de llamada antes de la definición de la función.

<?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) Una arquitectura basada en clase / OOP

Este es el ejemplo más común en los complementos de hoy en día.

<?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) Una arquitectura basada en clase / OOP con un objeto de configuración externo

Este escenario asume que tienes un archivo de complemento principal y un segundo archivo llamado setup.php en un subdirectorio del complemento llamado inc : ~/wp-content/plugins/your_plugin/inc/setup.php . Esto funcionará también cuando la carpeta del complemento esté fuera de la estructura de carpetas WP predeterminada, así como cuando se cambie el nombre del directorio de contenido o en los casos en que su archivo de configuración tenga un nombre diferente. Solo la carpeta inc debe tener el mismo nombre & ubicación relativa del directorio raíz de complementos.

Nota: simplemente puedes tomar las tres funciones register_*_hook()* y las clases y colocarlas en tu complemento.

El archivo del complemento 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;
    }
}

El archivo de instalación:

<?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) Actualizaciones de complementos

Si escribe un complemento que tiene su propia tabla de base de datos u opciones, puede haber situaciones en las que necesite cambiar o actualizar cosas.

Lamentablemente, hasta ahora no hay posibilidad de ejecutar algo en la instalación o actualización / actualización de un tema / tema. Con mucho gusto hay una solución alternativa: enganche una función personalizada a una opción personalizada (sí, es escaso, pero funciona).

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

Fuente

Esta función de actualización es un ejemplo no muy agradable / bien escrito, pero como se dijo: es un ejemplo y la técnica funciona bien. Mejorará eso con una actualización posterior.

    
respondido por el kaiser 15.08.2011 - 20:18
15

Para probar el sistema actual para las características requeridas, como la versión PHP o las extensiones instaladas, puedes usar algo así:

<?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__ ) );
}

Prueba con un cheque para PHP 5.5:

    
respondido por el fuxia 09.04.2013 - 20:45

Lea otras preguntas en las etiquetas