深入淺出WordPress插件開發:從零開始建立你嘅第一個自訂插件

4分鐘閱讀
2026-03-13
2026-06-03
1,889
當你透過以下連結購物,我會獲得佣金,對你嚟講冇額外成本。.

WordPress插件基礎與開發環境

喺開始寫代碼之前,理解WordPress插件嘅基本概念同埋搭建合適嘅開發環境係好重要。一個WordPress插件本質上係一個包含PHP代碼嘅文件夾,佢透過WordPress提供嘅豐富API嚟擴展核心功能。插件可以細到只係加一個短代碼,大到可以建立一個完整嘅管理系統。佢嘅核心思想係「唔好改核心代碼」,咁樣可以保證WordPress升級嘅時候,你嘅自訂功能唔會唔見咗。

為咗高效開發,你需要一個本地開發環境。可以用XAMPP、MAMP、Local by Flywheel或者Docker呢啲工具快速搭建一個包含PHP同MySQL嘅伺服器。然後,安裝一個最新嘅WordPress實例。喺開發過程中,建議喺wp-config.php檔案入面啟用WP_DEBUG,咁樣可以及時發現錯誤。

插件嘅「心臟」係一個主PHP檔案。呢個檔案嘅頭部註釋係佢嘅身份證,WordPress透過讀取呢啲元資訊嚟喺後台識別同管理插件。一個標準嘅插件主檔案頭部註釋如下所示:

推薦閱讀 乜嘢係 WordPress 主題

<?php
/**
 * Plugin Name: 我的第一个自定义插件
 * Plugin URI:  https://example.com/my-first-plugin
 * Description: 这是一个用于学习插件开发的简单插件,它将在文章末尾添加自定义内容。
 * Version:     1.0.0
 * Author:      开发者名称
 * License:     GPL v2 or later
 * Text Domain: my-first-plugin
 */

創建你嘅第一個功能插件

等我哋從一個實際嘅功能開始:喺網站嘅每篇文章內容末尾自動加一段自訂文字。呢個例子會貫穿插件開發嘅核心流程。

UltaHost WordPress 主機
30日退款保證,無限頻寬同數據庫,免費DDoS防護,買3年優惠50%

插件主檔案與初始化

首先,喺WordPress嘅wp-content/plugins目錄下開一個新資料夾,例如my-first-plugin。喺該文件夾內,創建主PHP檔案,可以命名為my-first-plugin.php。將上面嘅頭部註釋代碼複製入去。

跟住,我哋需要一個安全嘅方法去執行插件嘅初始化代碼。最佳實踐係將所有功能包裝喺一個類入面,或者用命名空間函數。呢度我哋用一個簡單嘅類去組織代碼。喺主文件頭部註釋之後,加入以下類定義:

if ( ! defined( 'ABSPATH' ) ) {
	exit; // 防止直接访问文件
}

class My_First_Plugin {
    public function __construct() {
        // 构造函数,在这里挂载钩子
    }
}

// 初始化插件
new My_First_Plugin();

if ( ! defined( ‘ABSPATH’ ) )呢行代碼係WordPress插件開發嘅安全標準,用嚟防止用戶直接透過URL訪問你嘅插件文件。

用鉤子加入文章頁尾內容

WordPress嘅插件架構係建立喺「鉤子」(Hooks)系統之上,分為動作(Action)同過濾器(Filter)。動作容許你喺特定時刻執行代碼,而過濾器就容許你修改數據。

推薦閱讀 WordPress網站性能優化終極指南:由基礎設定到快取插件全解析

我哋嘅目標係喺文章內容之後加啲文字,呢個係一個「過濾」內容嘅過程。所以,我哋會用the_content呢個過濾器。修改類入面嘅構造函數同方法如下:

class My_First_Plugin {
    public function __construct() {
        // 将自定义方法挂载到‘the_content’过滤器上
        add_filter( 'the_content', array( $this, 'add_footer_to_content' ) );
    }

/**
     * 在文章内容后添加自定义页脚
     *
     * @param string $content 原始文章内容。
     * @return string 修改后的文章内容。
     */
    public function add_footer_to_content( $content ) {
        // 确保只在主循环的单篇文章页面显示
        if ( is_single() &amp;&amp; in_the_loop() &amp;&amp; is_main_query() ) {
            $custom_footer = '<div class="my-plugin-footer"><p>多謝你睇呢篇文章!由【我嘅第一個插件】生成。</p></div>';
            $content .= $custom_footer;
        }
        return $content;
    }
}

add_filter()函數會將類方法add_footer_to_content註冊到the_content過濾器。當WordPress準備輸出文章內容時,會調用我哋嘅方法,並傳入原始內容。我哋通過條件判斷確保只喺單獨嘅文章頁面加頁腳,避免喺首頁、歸檔頁重複添加。最後,將自定義HTML追加到內容後面並返回。

為插件添加管理後台選項

一個成熟嘅插件通常允許用戶喺後台進行配置。我哋會為啱啱嘅頁腳文本添加一個簡單嘅設定選項,等用戶可以自定義顯示嘅文字。

hosting.com 共享主機
高效能,配備 AMD EPYC 處理器、NVMe SSD 儲存同 LiteSpeed,提供全天候專業內部支援,採用先進安全措施,包括 SSL、暴力破解、惡意軟件同 DDoS 防護,可節省高達 73%。

創建設置選單頁面

我哋需要喺WordPress管理後台嘅「設定」選單下面加一個子頁面。呢個需要用到add_options_page()函數,通常會掛載喺admin_menu動作鈎上面。

首先,喺插件類度新增一個方法嚟註冊選單同頁面:

class My_First_Plugin {
    // ... 之前的构造函数和方法 ...

public function __construct() {
        add_filter( 'the_content', array( $this, 'add_footer_to_content' ) );
        // 挂载后台管理菜单
        add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
        // 挂载初始化设置选项
        add_action( 'admin_init', array( $this, 'settings_init' ) );
    }

public function add_admin_menu() {
        add_options_page(
            '我的第一个插件设置', // 页面标题
            '自定义页脚设置',     // 菜单标题
            'manage_options',     // 所需权限
            'my-first-plugin',    // 菜单slug
            array( $this, 'options_page_html' ) // 回调函数,用于输出页面HTML
        );
    }
}

註冊設定欄位同埋渲染頁面

跟住落嚟,我哋需要用WordPress Settings API嚟安全地註冊、保存同埋驗證選項。呢個步驟涉及register_setting(), add_settings_section()同埋add_settings_field()等函數。

推薦閱讀 WooCommerce 是什么?一文详解其核心功能与应用场景

public function settings_init() {
    // 注册一个设置选项组
    register_setting( 'my_first_plugin_settings', 'my_first_plugin_options' );

// 在页面中添加一个设置区域
    add_settings_section(
        'my_first_plugin_section',
        '页脚内容配置',
        array( $this, 'section_callback' ),
        'my-first-plugin'
    );

// 向该区域添加一个字段
    add_settings_field(
        'footer_text',
        '页脚显示文本',
        array( $this, 'footer_text_field_render' ),
        'my-first-plugin',
        'my_first_plugin_section'
    );
}

public function section_callback() {
    echo '<p>喺呢度設定顯示喺文章結尾嘅文字內容。</p>';
}

public function footer_text_field_render() {
    $options = get_option( 'my_first_plugin_options' );
    $value = $options['footer_text'] ?? '感谢阅读本文!由【我的第一个插件】生成。'; // 默认值
    ?&gt;
    <input type='text' name='my_first_plugin_options[footer_text]' value='<?php echo esc_attr( $value ); ?>' style='width: 400px;'>
    <p class="description">支援簡單嘅HTML標籤,例如 <strong>, <em>, <a>。</p>
    <?php
}

public function options_page_html() {
    // 检查用户权限
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action='/yue/options.php/' method='post' data-trp-original-action="options.php">
            <?php
            settings_fields( 'my_first_plugin_settings' );
            do_settings_sections( 'my-first-plugin' );
            submit_button();
            ?>
        <input type="hidden" name="trp-form-language" value="yue"/></form>
    </div>
    &lt;?php
}

最後,修改前端輸出函數add_footer_to_content,等佢可以從數據庫選項度讀取文字:

public function add_footer_to_content( $content ) {
    if ( is_single() &amp;&amp; in_the_loop() &amp;&amp; is_main_query() ) {
        $options = get_option( 'my_first_plugin_options' );
        $footer_text = $options['footer_text'] ?? '感谢阅读本文!由【我的第一个插件】生成。';
        $custom_footer = '<div class="my-plugin-footer"><p>' . wp_kses_post( $頁尾文字 ) . '</p></div>';
        $content .= $custom_footer;
    }
    return $content;
}

wp_kses_post()個函數確保咗用戶輸入嘅文本入面只會出現安全嘅HTML標籤,呢個係好重要嘅安全措施。

InterServer 共享主機
共享主機:每月1TB,只需£2.50;首月只需£0.10,使用優惠碼 tryinterserver。461個雲端應用程式腳本,一鍵安裝。

插件國際化與最佳實踐

為咗令個插件可以俾全世界嘅用戶用到,國際化(i18n)係必不可少嘅一步。WordPress用GNU gettext框架嚟實現翻譯。

文本域同翻譯函數

首先,確保你個插件頭部註釋入面定義咗Text Domain,例如my-first-plugin。然後,喺插件入面所有需要翻譯嘅字串位置,用特定嘅函數包住。

修改我哋之前嘅代碼,為輸出文本加上翻譯支援:

// 在构造函数中加载翻译文件
public function __construct() {
    // ... 其他钩子 ...
    add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
}

public function load_textdomain() {
    load_plugin_textdomain(
        'my-first-plugin',
        false,
        dirname( plugin_basename( __FILE__ ) ) . '/languages/'
    );
}

// 修改设置页面的字符串
public function section_callback() {
    echo '<p>' . esc_html__( '在这里配置显示在文章末尾的文本内容。', 'my-first-plugin' ) . '</p>';
}

public function footer_text_field_render() {
    $options = get_option( 'my_first_plugin_options' );
    $value = $options['footer_text'] ?? __( '感谢阅读本文!由【我的第一个插件】生成。', 'my-first-plugin' );
    ?&gt;
    <input type='text' name='my_first_plugin_options[footer_text]' value='<?php echo esc_attr( $value ); ?>' style='width: 400px;'>
    <p class="description">&lt;?php esc_html_e( &#039;支持简单的HTML标签,如 <strong>, <em>, <a>。', 'my-first-plugin' ); ?&gt;</p>
    &lt;?php
}

// 注意:用户在前台输入的“页脚文本”本身通常不需要翻译,因为它是由管理员设置的具体内容。

__()用嚟翻譯同埋傳返字串,esc_html__()用嚟翻譯同埋跳脫HTML輸出,_e()用於翻譯並直接回傳字串。函數第二個參數係文字域,必須同插件定義嘅保持一致。

安全、性能同代碼組織

除咗國際化,仲需要跟住以下最佳實踐:
1. 安全:对所有用户输入进行验证、清理和转义。使用sanitize_text_field(), esc_html(), wp_kses_post()等函數。使用wp_nonce_field()防止CSRF攻擊。
2. 性能:合理使用钩子,避免在每次页面加载时执行不必要的数据库查询。可以考虑对输出结果进行 transient 缓存。
3. 代码组织:对于复杂的插件,应将文件按功能模块拆分。主文件负责引导,类和方法放在includes/目錄,前端資產(CSS, JS)放喺assets/目錄。
4. 卸载清理:如果你的插件创建了数据库表或选项,应该提供卸载功能来清理数据。可以通过一个独立的uninstall.php檔案嚟實現。

摘要

透過呢個教程,我哋完成咗一個具備基礎功能嘅WordPress自定義插件嘅完整開發流程:從搭建環境、創建插件骨架、利用掛鉤系統添加功能,到實現後台設置頁面,最後涵蓋國際化同安全實踐。你學識咗點樣使用add_filter同埋add_action同WordPress核心互動,點樣使用Settings API創建可靠嘅選項頁面,以及點樣透過load_plugin_textdomain令插件支援多語言。記住,開發插件嗰陣,安全、可維護性同用戶體驗係首要考慮因素。以呢個為基礎,你可以繼續探索自定義文章類型、元數據、短代碼、REST API端點等更高級嘅功能,構建更強大嘅WordPress擴展。

常見問題

點解我嘅插件喺後台選單度唔顯示出嚟?

呢個通常係因為權限問題或者代碼錯誤造成。首先,請確保你嘅add_options_pageadd_menu_page函數中指定嘅權限參數(例如‘manage_options’)同你而家登入嘅用戶角色匹配。其次,檢查admin_menu掛鈎係咪正確掛載,同埋回呼函數有冇語法錯誤搞到PHP執行中斷。最簡單嘅方法係喺WordPress後台啟用WP_DEBUG,睇吓有冇相關嘅錯誤訊息輸出。

點樣為插件加自訂CSS同JavaScript檔案?

正確嘅做法係使用wp_enqueue_style()同埋wp_enqueue_script()函數。對於前端資源,應該掛載到wp_enqueue_scripts動作鈎子上;對於管理後台資源,則掛載到admin_enqueue_scripts掛咗鈎

喺你嘅插件類入面,可以加入以下方法:

public function enqueue_frontend_assets() {
    wp_enqueue_style( ‘my-plugin-style’, plugin_dir_url( __FILE__ ) . ‘assets/css/style.css’, array(), ‘1.0.0’ );
}

然後喺構造函數入面通過add_action( ‘wp_enqueue_scripts’, array( $this, ‘enqueue_frontend_assets’ ) );註冊。咁樣可以確保依賴管理正確,而且唔會同其他插件或者主題撞。

用戶解除安裝插件嗰陣,點樣清理我建立嘅數據選項?

WordPress提供咗兩種主要方法。第一種係註冊一個解除安裝掛鉤,但係呢個喺面向對象嘅插件入面唔係好常用。更加推薦、亦都更加標準嘅方法係建立一個uninstall.php檔案,佢同你嘅主插件檔案係同級嘅。

當用戶透過WordPress後台刪除插件嗰陣,WordPress會自動檢查同執行呢個檔案。喺uninstall.php入面,你需要先檢查WP_UNINSTALL_PLUGIN常數係咪有被定義,然後安全噉刪除插件創建嘅所有選項、自訂數據庫表等等嘅資料。例如:

if ( ! defined( ‘WP_UNINSTALL_PLUGIN’ ) ) {
    exit;
}
delete_option( ‘my_first_plugin_options’ );
// 如果有自定义表:$wpdb->query( “DROP TABLE IF EXISTS {$wpdb->prefix}my_table” );

我個插件點樣可以兼容更多版本嘅WordPress?

保持兼容性嘅關鍵在於慎用新版本嘅函數同特性,並為舊版本提供替代方案。喺調用可能喺新版本先存在嘅函數之前,使用function_exists()進行檢查。例如,如果你要使用5.0版本引入嘅wp_date函數,可以:

if ( function_exists( ‘wp_date’ ) ) {
    $date = wp_date( get_option( ‘date_format’ ), $timestamp );
} else {
    $date = date_i18n( get_option( ‘date_format’ ), $timestamp );
}

同時,喺插件頭部註釋同readme檔案中明確聲明測試過嘅最低WordPress版本。定期喺較舊嘅WordPress版本上進行測試係確保兼容性嘅最好方法。