Gỡ cài đặt, kích hoạt, hủy kích hoạt plugin: các tính năng tiêu biểu và cách thực hiện


100

Tôi đang tạo một plugin wordpress. Những điều điển hình tôi nên bao gồm trong tính năng gỡ cài đặt là gì?

Ví dụ, tôi có nên xóa bất kỳ bảng nào tôi đã tạo trong hàm cài đặt không?

Tôi có làm sạch các mục tùy chọn của tôi?

Còn gì nữa không?


Tôi đã lãng phí quá nhiều thời gian để cố gắng làm cho nó hoạt động. Vấn đề là hook init không hoạt động bên trong hook hook. Tôi cho rằng không một hook (hành động hoặc bộ lọc) sẽ không hoạt động sớm như vậy. Đọc các ghi chú bằng liên kết dưới đây. codex.wordpress.org/Function_Reference/register_activation_hook Nó nói: "Đăng ký móc bên trong móc plugins_loaded của bạn là quá muộn và nó sẽ không chạy (Ngay cả khi nó có vẻ làm việc cho đến khi register_deactivation_hook móc wp_loaded.)!"
Anton

Tôi là người đã cập nhật codex theo những gì bạn đã đề cập, vì vậy điều này được xem xét trong câu trả lời ở trên. :)
kaiser

Câu trả lời:


150

Có ba móc khác nhau . Họ kích hoạt trong các trường hợp sau:

  • Gỡ cài đặt
  • Chấm dứt hoạt
  • Kích hoạt

Cách kích hoạt các chức năng một cách an toàn trong các tình huống

Dưới đây cho thấy các cách thích hợp để móc các hàm gọi lại một cách an toàn được kích hoạt trong các hành động được đề cập.

Như bạn có thể sử dụng mã này trong một plugin sử dụng

  • chức năng đơn giản,
  • một lớp học hoặc
  • một lớp bên ngoài,

Tôi sẽ hiển thị ba plugin demo khác nhau mà bạn có thể kiểm tra và sau đó sẽ triển khai mã trong (các) plugin của riêng bạn.

Lưu ý quan trọng trả trước!

Vì chủ đề này là vô cùng khó khăn và rất chi tiết và có hàng tá trường hợp + cạnh, câu trả lời này sẽ không bao giờ hoàn hảo. Tôi sẽ tiếp tục cải thiện nó theo thời gian, vì vậy hãy kiểm tra lại trên cơ sở thường xuyên.

(1) Kích hoạt / Hủy kích hoạt / Gỡ cài đặt plugin.

Các cuộc gọi lại thiết lập plugin được kích hoạt bởi lõi và bạn không có ảnh hưởng đến cách lõi thực hiện việc này. Có một số điều cần lưu ý:

  • Không bao giờ , echo/printbất cứ điều gì (!) Trong khi gọi lại thiết lập. Điều này sẽ dẫn đến headers already senttin nhắn và cốt lõi sẽ khuyến nghị hủy kích hoạt và xóa plugin của bạn ... đừng hỏi: Tôi biết ...
  • Bạn sẽ không thấy bất kỳ đầu ra trực quan. Nhưng tôi đã thêm các exit()câu lệnh vào tất cả các cuộc gọi lại khác nhau để bạn có thể hiểu thêm về những gì đang thực sự xảy ra. Chỉ cần bỏ qua cho họ để xem công cụ làm việc.
  • Điều cực kỳ quan trọng là bạn kiểm tra xem __FILE__ != WP_PLUGIN_INSTALLvà (nếu không: hủy bỏ!) Để xem liệu có thực sự gỡ cài đặt plugin hay không. Tôi khuyên bạn chỉ nên kích hoạt các on_deactivation()cuộc gọi lại trong quá trình phát triển, vì vậy bạn hãy tiết kiệm thời gian mà bạn cần để lấy lại mọi thứ. Ít nhất đây là những gì tôi làm.
  • Tôi cũng làm một số công cụ bảo mật. Một số được thực hiện bởi cốt lõi là tốt, nhưng hey! Cẩn tắc vô ưu! .
    • Đầu tiên tôi không cho phép truy cập tệp trực tiếp khi lõi không được tải: defined( 'ABSPATH' ) OR exit;
    • Sau đó tôi kiểm tra xem người dùng hiện tại có được phép thực hiện tác vụ này không.
    • Như một nhiệm vụ cuối cùng, tôi kiểm tra người giới thiệu. Lưu ý: Có thể có kết quả không mong muốn với wp_die()màn hình yêu cầu quyền thích hợp (và nếu bạn muốn thử lại ... vâng, chắc chắn ), khi bạn gặp lỗi. Điều này xảy ra như lõi chuyển hướng bạn, thiết lập hiện tại $GLOBALS['wp_list_table']->current_action();để error_scraperồi kiểm tra giới thiệu cho check_admin_referer('plugin-activation-error_' . $plugin);, đâu $plugin$_REQUEST['plugin']. Vì vậy, chuyển hướng xảy ra ở một nửa tải trang và bạn nhận được thanh cuộn có dây này và màn hình chết nhìn rõ hộp thông báo / thông báo quản trị viên màu vàng. Nếu điều này xảy ra: Hãy bình tĩnh và chỉ tìm kiếm lỗi với một số exit()và từng bước gỡ lỗi.

(A) Plugin chức năng đơn giản

Hãy nhớ rằng điều này có thể không hoạt động nếu bạn nối các cuộc gọi lại trước khi định nghĩa hàm.

<?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) Một kiến ​​trúc dựa trên lớp / OOP

Đây là ví dụ phổ biến nhất trong các plugin hiện nay.

<?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) Một kiến ​​trúc dựa trên lớp / OOP với một đối tượng thiết lập bên ngoài

Kịch bản này giả định rằng bạn có một tệp plugin chính và một tệp thứ hai có tên setup.phptrong thư mục con của plugin có tên inc: ~/wp-content/plugins/your_plugin/inc/setup.php. Điều này cũng sẽ hoạt động khi thư mục plugin nằm ngoài cấu trúc thư mục WP mặc định, cũng như khi thư mục nội dung được đổi tên hoặc trong trường hợp tệp thiết lập của bạn được đặt tên khác. Chỉ incthư mục phải có cùng tên và vị trí liên quan từ thư mục gốc của plugin.

Lưu ý: Bạn có thể chỉ cần lấy ba register_*_hook()*hàm và các lớp và thả chúng vào plugin của bạn.

Tệp plugin chính:

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

Tệp cài đặt:

<?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) Cập nhật plugin

Nếu bạn viết một plugin có bảng DB hoặc các tùy chọn riêng, có thể có các kịch bản mà bạn cần thay đổi hoặc nâng cấp mọi thứ.

Đáng buồn thay cho đến nay không có khả năng để chạy một cái gì đó trên cài đặt plugin / chủ đề hoặc cập nhật / nâng cấp. Rất vui vì có một cách giải quyết: Kết nối một chức năng tùy chỉnh với một tùy chọn tùy chỉnh (vâng, nó khập khiễng - nhưng nó hoạt động).

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

Nguồn

Hàm cập nhật này là một ví dụ không hay / được viết tốt, nhưng như đã nói: Đó là một ví dụ và kỹ thuật hoạt động tốt. Sẽ cải thiện điều đó với một bản cập nhật sau.


1
Đây là điều tuyệt vời NHƯNG điều tôi thực sự muốn biết là những điều tôi nên đưa vào phương thức hủy kích hoạt của mình ... ví dụ: tôi có nên xóa các bảng của mình trong cơ sở dữ liệu hay để chúng trong trường hợp người dùng thay đổi ý định và kích hoạt lại plugin ?
tái khám phá

1
Quảng cáo "NHƯNG": Tôi đã đề cập rằng có 3 phương pháp. Một cho kích hoạt, một cho hủy kích hoạt tạm thời và một cho hủy kích hoạt. Imho "gỡ cài đặt" nói "Xóa tôi và mọi thứ tôi đã làm", trong khi "hủy kích hoạt" là trạng thái tạm thời và có thể được làm lại. Nhưng: Xem cập nhật. Tôi đã thêm ý kiến ​​về Q + của bạn mở rộng nó với một số khuyến nghị phát triển.
kaiser

3
À tôi hiểu rồi. Chỉ là một câu hỏi, khi nào gỡ cài đặt được gọi? Khi các tập tin bị xóa ??
tái khám phá

1
@aendrew Chúng chỉ được sử dụng ở bên check_admin_referer(). Họ không cần phải vệ sinh vì lõi không tự làm được và dù sao cũng sẽ so sánh nó với các $_REQUESTgiá trị không được xác nhận. Nhưng nếu họ bắt đầu khóc như những cô gái nhỏ vì điều đó, chỉ cần sử dụng filter_var()hoặc esc_attr()trên nó.
kaiser

2
Bạn không nên kiểm tra WP_UNINSTALL_PLUGIN trong chức năng gọi lại nếu sử dụng wp_register_uninstall_hook, chỉ khi bạn sử dụng Gỡ cài đặt.php
paul

17

Để kiểm tra hệ thống hiện tại cho các kỳ công cần thiết như phiên bản PHP hoặc các tiện ích mở rộng đã cài đặt, bạn có thể sử dụng một cái gì đó tương tự:

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

Kiểm tra với một kiểm tra cho PHP 5.5:

nhập mô tả hình ảnh ở đây


Cảm thấy bối rối, vì vậy về cơ bản không có cuộc gọi đến register_activation_hookđây - tại sao không sử dụng nó? Ngoài ra, ngọn lửa này sẽ trước hoặc sau register_activation_hookvà sẽ register_activation_hookbắn ngay cả khi những điều trên không vượt qua?
orionrush

Nó chỉ chạy sau hook kích hoạt trên trang plugin.
fuxia

Tôi thấy - nhưng nếu plugin được kích hoạt bên ngoài trang plugin (giả sử là một phần của phụ thuộc chủ đề) thì kiểm tra của bạn có bị bỏ qua không? Vì vậy, tôi đã thử chuyển add_action( 'admin_notices', 't5_check_admin_notices', 0 );vào một cái móc kích hoạt và plugin kích hoạt mà không thực hiện kiểm tra. . .
orionrush

@kaiser đã giải thích cách móc kích hoạt hoạt động, tôi muốn hiển thị một thay thế. Nếu plugin không được kích hoạt trên mỗi trang plugin thì có thể xảy ra lỗi nghiêm trọng. Cách tiếp cận này không thể hoạt động trên một cái móc kích hoạt mà không cần viết lại nghiêm túc, bởi vì cái móc đó kích hoạt sau đó admin_notices.
fuxia

Trên thực tế chỉ cần vấp ngã một cách dễ dàng: stackoverflow.com/a/13927297/362445
orionrush
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.