Desinstalar, Ativar, Desativar um plugin: características típicas e instruções

91

Eu estou fazendo um plugin para wordpress. Quais são as coisas típicas que devo incluir no recurso de desinstalação?

Por exemplo, devo deletar alguma tabela que criei na função de instalação?

Limpo minhas entradas de opção?

Mais alguma coisa?

    
por redconservatory 15.08.2011 / 01:21
fonte

2 respostas

139

Existem três diferentes ganchos. Eles acionam nos seguintes casos:

  • Desinstalar
  • Desativação
  • Ativação

Como disparar funções com segurança durante os cenários

O seguinte mostra as maneiras certas de enganchar com segurança as funções de retorno de chamada que são acionadas durante as ações mencionadas.

Como você pode usar esse código em um plug-in que usa

  • funções simples,
  • uma turma ou
  • uma classe externa,

Vou mostrar três plugins de demonstração diferentes que você pode inspecionar e depois implementar o código em seu (s) próprio (s) plug-in (s).

Nota importante antecipadamente!

Como este tópico é extremamente difícil e muito detalhado e tem uma dúzia de casos + de borda, esta resposta nunca será perfeita. Eu vou continuar melhorando ao longo do tempo, então volte em uma base regular.

(1) Ativar / desativar / desinstalar plug-ins.

Os callbacks de configuração do plugin são acionados pelo core e você tem não influência sobre como o core faz isso. Existem algumas coisas para ter em mente:

  • Nunca , sempre echo/print anything (!) durante os retornos de chamada de configuração. Isso levará a headers already sent mensagem e núcleo irá recomendar para desativar e excluir o seu plugin ... não pergunte: eu sei ...
  • Você não verá qualquer saída visual. Mas Adicionei exit() declarações a todos os diferentes retornos de chamada para que você possa obter algumas informações sobre o que realmente está acontecendo. Apenas descomente-os para ver as coisas funcionando.
  • É extremamente importante que você verifique se __FILE__ != WP_PLUGIN_INSTALL e (se não: abortar!) para ver se está realmente desinstalando o plugin. Eu recomendaria simplesmente acionar on_deactivation() retornos de chamada durante o desenvolvimento, para que você economize o tempo necessário para recuperar tudo. Pelo menos é o que eu faço.
  • Eu também faço algumas coisas de segurança. Alguns são feitos pelo núcleo também, mas ei! Melhor prevenir do que remediar! .
    • Primeiro, eu desautorizo o acesso direto a arquivos quando o núcleo não está carregado: defined( 'ABSPATH' ) OR exit;
    • Depois, verifico se o usuário atual pode realizar essa tarefa.
    • Como última tarefa, verifico o referenciador. Observação: pode haver resultados inesperados com uma tela wp_die() solicitando permissões adequadas (e se você quiser tentar novamente ... sim, com certeza ), quando tiver um erro. Isso acontece quando o núcleo o redireciona, define o% atual$GLOBALS['wp_list_table']->current_action(); para error_scrape e, em seguida, verifica o referenciador para check_admin_referer('plugin-activation-error_' . $plugin); , em que $plugin é $_REQUEST['plugin'] . Assim, o redirecionamento acontece na metade do carregamento da página e você obtém essa barra de rolagem com fio e a tela da matriz insight a caixa de mensagem / aviso do administrador amarelo. Se isso acontecer: mantenha a calma e apenas procure o erro com algum exit() e depuração passo a passo.

(A) Plugin de funções simples

Lembre-se de que isso pode não funcionar se você ligar os callbacks antes da definição da função.

<?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) Uma arquitetura baseada em classes / OOP

Este é o exemplo mais comum nos plugins de hoje em dia.

<?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) Uma arquitetura baseada em classe / OOP com um objeto de configuração externo

Este cenário pressupõe que você tenha um arquivo de plug-in principal e um segundo arquivo chamado setup.php em um subdiretório do plug-in denominado inc : ~/wp-content/plugins/your_plugin/inc/setup.php . Isso funcionará também quando a pasta do plug-in estiver fora da estrutura de pastas padrão do WP, bem como quando o diretório de conteúdo for renomeado ou nos casos em que o arquivo de instalação tiver um nome diferente. Apenas a pasta inc precisa ter o mesmo nome & localização relativa do diretório raiz dos plugins.

Nota: Você pode simplesmente pegar as três funções register_*_hook()* e as classes e soltá-las no seu plugin.

O arquivo principal do plug-in:

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

O arquivo de configuração:

<?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) Atualizações de plug-ins

Se você escrever um plug-in que tenha sua própria tabela ou opções do banco de dados, poderá haver cenários em que você precisará alterar ou atualizar as coisas.

Infelizmente, até agora não há possibilidade de executar algo na instalação do plugin / theme ou atualizar / atualizar. Com prazer, há uma solução alternativa: ligar uma função personalizada a uma opção personalizada (sim, é ruim - mas 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' );

Fonte

Esta função de atualização é um exemplo não tão bom / bem escrito, mas como dito: É um exemplo e a técnica funciona bem. Melhorará isso com uma atualização posterior.

    
por kaiser 15.08.2011 / 20:18
fonte
15

Para testar o sistema atual em busca de recursos necessários, como a versão do PHP ou extensões instaladas, você pode usar algo assim:

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

Teste com uma verificação para o PHP 5.5:

    
por fuxia 09.04.2013 / 20:45
fonte