플러그인 제거, 활성화, 비활성화 : 일반적인 기능 및 방법


100

워드 프레스 플러그인을 만들고 있습니다. 제거 기능에 포함해야 할 일반적인 사항은 무엇입니까?

예를 들어, 설치 기능에서 작성한 테이블을 삭제해야합니까?

옵션 항목을 정리합니까?

다른 거있어?


나는 그것을 작동 시키려고 너무 많은 시간을 낭비했다. 문제는 등록 후크 내에서 init 후크가 작동하지 않는다는 것입니다. 하나의 후크 (동작 또는 필터)가 그렇게 빨리 작동하지 않을 것이라고 가정합니다. 아래 링크로 메모를 읽으십시오. codex.wordpress.org/Function_Reference/register_activation_hook는 그것은 말한다 : "당신의 plugins_loaded 후크 내부의 훅을 등록 너무 늦기 그것은 실행되지 않습니다 (가 wp_loaded 후크까지 register_deactivation_hook을 위해 작동하는 것 같다 경우에도.)!"
안톤

나는 당신이 언급 한대로 코덱을 업데이트 한 사람이므로 위의 ↑ 답변에서 고려됩니다. :)
kaiser February

답변:


150

가지 후크가 있습니다. 다음과 같은 경우에 트리거됩니다.

  • 제거
  • 비활성화
  • 활성화

시나리오 중 기능을 안전하게 트리거하는 방법

다음은 언급 된 동작 중에 트리거되는 콜백 함수를 안전하게 후크 하는 올바른 방법을 보여줍니다 .

이 코드를 사용하는 플러그인에서 사용할 수 있으므로

  • 일반 기능,
  • 수업 또는
  • 외부 수업

검사 할 수있는 세 가지 데모 플러그인 을 보여 드리고 나중에 자체 플러그인으로 코드를 구현할 것입니다.

중요한 참고 사항!

이 주제는 매우 어렵고 매우 상세하며 수십 가지 이상의 사례가 있으므로이 답변은 완벽하지 않습니다. 시간이 지남에 따라 계속 개선 할 것이므로 정기적으로 다시 확인하십시오.

(1) 플러그인 활성화 / 비활성화 / 제거

플러그인 설정 콜백은 코어에 의해 트리거되며 코어가이를 수행하는 방법 에는 영향을 미치지 않습니다. 명심해야 할 것이 있습니다.

  • 결코 , 이제까지 echo/print설정 콜백 동안 아무것도 (!). 이것은 headers already sent메시지로 이어지고 핵심은 플러그인을 비활성화하고 삭제하는 것이 좋습니다 ... 묻지 않습니다 : 알아요 ...
  • 당신은하지 않습니다 시각적 출력을. 그러나 나는 exit()모든 다른 콜백 에 진술을 추가 하여 실제로 일어나는 일에 대한 통찰력을 얻을 수 있습니다. 작동을 확인하려면 주석 처리를 제거하십시오.
  • __FILE__ != WP_PLUGIN_INSTALL플러그인이 실제로 제거되는지 여부 를 확인하는 것이 매우 중요합니다 . on_deactivation()개발 중에 단순히 콜백을 트리거하는 것이 좋습니다 . 따라서 모든 것을 다시 가져와야하는 시간을 절약 할 수 있습니다. 적어도 이것이 내가하는 일입니다.
  • 나도 몇 가지 보안 작업을 수행합니다. 일부는 코어로도 이루어 지지만 이봐! 죄송합니다보다 더 안전! .
    • 먼저 코어가로드되지 않은 경우 직접 파일 액세스를 허용하지 않습니다. defined( 'ABSPATH' ) OR exit;
    • 그런 다음 현재 사용자가이 작업을 수행 할 수 있는지 확인합니다.
    • 마지막 작업으로 리퍼러를 확인합니다. 참고 : 오류가 발생했을 때 wp_die()화면에 적절한 권한을 요청하는 (그리고 다시 시도하려는 경우 ... 예, 확실히 ) 예상치 못한 결과가 발생할 수 있습니다 . 코어, 리디렉션 전류를 설정 이것은 발생 $GLOBALS['wp_list_table']->current_action();error_scrape다음의 참조 페이지를 확인 check_admin_referer('plugin-activation-error_' . $plugin);어디에 $plugin이다 $_REQUEST['plugin']. 따라서 리디렉션은 페이지로드의 절반에서 발생 하며이 유선 스크롤 막대와 다이 화면에 노란색 관리자 알림 / 메시지 상자가 나타납니다. 이 경우 : 침착성을 유지하고 exit()단계별 디버깅으로 오류를 검색하십시오 .

(A) 일반 기능 플러그인

함수 정의 전에 콜백을 연결하면 작동하지 않을 수 있습니다.

<?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) 클래스 기반 / OOP 아키텍처

이것은 오늘날 플러그인에서 가장 일반적인 예입니다.

<?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) 외부 설정 객체가있는 클래스 기반 / OOP 아키텍처

이 시나리오는 메인 플러그인 파일과라는 이름의 두 번째 파일 가지고 있다고 가정 setup.php라는 이름의 플러그인의 하위 디렉토리에을 inc: ~/wp-content/plugins/your_plugin/inc/setup.php. 이는 플러그인 폴더가 기본 WP 폴더 구조를 벗어나거나 컨텐츠 디렉토리의 이름이 바뀌거나 설정 파일의 이름이 다른 경우에도 효과적입니다. 만 inc폴더는 플러그인의 루트 디렉토리에서 같은 이름 및 위치 관련을 가지고있다.

참고 : 단순히 세 가지 register_*_hook()*기능과 클래스를 가져 와서 플러그인에 넣을 수 있습니다.

기본 플러그인 파일 :

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

설정 파일 :

<?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) 플러그인 업데이트

자체 DB 테이블 또는 옵션이있는 플러그인을 작성하는 경우 변경하거나 업그레이드해야하는 시나리오가있을 수 있습니다.

슬프게도 지금까지 플러그인 / 테마 설치 또는 업데이트 / 업그레이드에서 무언가를 실행할 가능성이 없습니다. 다행스럽게도 해결 방법이 있습니다 : 사용자 정의 함수를 사용자 정의 옵션에 연결하십시오 (예, 절름발이이지만 작동합니다).

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

출처

이 업데이트 기능은 좋지 않은 / 잘 작성된 예이지만, 예를 들면 다음과 같습니다. 이후 업데이트로 개선 할 것입니다.


1
이것은 내가 정말로 알고 싶은 것은 비활성화 방법에 포함시켜야하는 것들입니다. 예를 들어, 데이터베이스에서 테이블을 삭제하거나 사용자가 마음을 바꾸고 플러그인을 다시 활성화하는 경우 테이블을 남겨 두어야합니다 ?
redconservatory

1
광고 "하지만": 3 가지 방법이 있다고 언급했습니다. 하나는 활성화, 하나는 일시적 비활성화 및 중지되지 않은 것입니다. Imho "제거"는 "나와 내가 한 모든 것을 제거합니다"라고 말하고 "비활성화"는 일시적인 상태이며 다시 실행할 수 있습니다. 그러나 : 업데이트를 참조하십시오. Q +에 대한 의견을 추가하여 일부 개발 권장 사항으로 확장했습니다.
카이저

3
아 이해가되었습니다. 언제 제거가 호출됩니까? 파일이 삭제되면 ??
redconservatory

1
@aendrew 측면에서만 사용됩니다 check_admin_referer(). 핵심은 자체적으로 수행하지 않으므로 위생되지 않은 $_REQUEST값 과 비교하기 때문에 위생 처리 할 필요가 없습니다 . 그들은 그 때문에 어린 소녀처럼 울고 시작한다면, 바로 사용 filter_var()또는 esc_attr()그것에.
카이저

2
uninstall.php를 사용하는 경우에만 wp_register_uninstall_hook을 사용하는 경우 콜백 함수에서 WP_UNINSTALL_PLUGIN을 확인해서는 안됩니다.
paul

17

현재 버전에서 PHP 버전 또는 설치된 확장 기능과 같은 필수 기능을 테스트하려면 다음과 같이 사용할 수 있습니다.

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

PHP 5.5 검사로 테스트하십시오.

여기에 이미지 설명을 입력하십시오


터치가 혼란 스럽기 때문에 기본적으로 register_activation_hook여기에 대한 호출이 없습니다. 왜 사용하지 않습니까? 또한 이전 또는 이후이 불 것 register_activation_hook하고는 것이다 register_activation_hook위에서 통과하지 않는 경우에도 해고?
orionrush

플러그인 페이지의 활성화 후크 후에 만 ​​실행됩니다.
fuxia

알지만 플러그인이 플러그인 페이지 외부에서 활성화되면 (예 : 테마 종속성의 일부) 검사가 생략되지 않습니까? 그래서 나는 add_action( 'admin_notices', 't5_check_admin_notices', 0 );활성화 후크로 이동 을 시도 하고 플러그인은 확인을 수행하지 않고 활성화합니다. . .
orionrush

@kaiser는 활성화 훅이 어떻게 작동하는지 설명했습니다. 대안을 보여주고 싶었습니다. 플러그인 페이지 당 플러그인이 활성화되지 않으면 치명적인 오류가 발생할 수 있습니다. 이 방법은 심각한 재 작성없이 활성화 후크에서 작동 할 수 없습니다 admin_notices. 후크는 이후에 실행되기 때문입니다 .
fuxia

실제로는 쉬운 길을 우연히 발견했습니다 : stackoverflow.com/a/13927297/362445
orionrush
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.