初始化一個WordPress外掛

呈上篇 “在WordPress中建立外掛的方法

當外掛檔案被啟用並載入後,就可以在主檔案內開始撰寫PHP程式碼

WordPress並沒有規定要如何架構外掛程式碼(檔案架構、模組化等等),但有給出一個Code Style的規範,可參考 PHP Coding Standards, wordpress.org

可以直接就執行一些動作

<?php
// register hook
add_action('wp_head', 'octopuswp_foo_bar');
function octopuswp_foo_bar()
{
    // do something in hooked function
}

// do something
$order = wc_get_order(123);
$order->update_meta_data('_foo', 'bar');
$order->save();

但,這樣的作法可能會有問題,以上列程式碼為例

  1. octopuswp_foo_bar 定義在全域下,可能會與其他第三方外掛的名稱衝突
  2. 用到了WooCommerce的wc_get_order,如果你的外掛在WooCommerce之前被載入,那這行就會出錯,因為找不到wc_get_order這個function,WordPress會依照資料夾名稱順序去載入外掛

考慮到WordPress的生態系,會用其他第三方外掛,都命名在全域下,會有名稱衝突的風險,因此最好的做法是OOP,將外掛包成一個類別

<?php
// 判斷類別是否已經存在這個Class
if(!class_exists('OctopusWP_Plugin')) {
    class OctopusWP_Plugin
    {
        public function __construct()
        {
            $this->register_hooks();
            $order = wc_get_order(123);
        }

        /**
         * 註冊所有hooks
         */
        private function register_hooks()
        {
            // hook後面給的都是一個"可被呼叫的"的函式名稱,因為foo_bar是這個類別的方法,所以必須要傳入這個類別的實體(instance),才可在外部被呼叫,且foo_bar必須為public
            add_action('wp_head', [$this, 'foo_bar']);
        }

        public function foo_bar()
        {
            // do something
        }
    }
    // 初始化
    new OctopusWP_Plugin();
}

透過類別,來限制外掛的命名域,類別內方法重複並沒有關係,只要類別名稱不重複就好

呈上述問題2,這樣直接new出來的方式,例如上面程式碼的建構式內還是有用到了wc_get_order,如果外掛在WooCommerce前被載入的話,還是會出錯,假如你的外掛是依賴在某個外掛下面,例如是一個WooCommerce用的金流外掛或是物流外掛,那最好是確保你的外掛載入在WooCommerce後,可以使用

<?php
// 判斷類別是否已經存在這個Class
if(!class_exists('OctopusWP_Plugin')) {
    class OctopusWP_Plugin
    {
        // 存放外掛類別的instance
        public static $instance;

        // 取得此類別的instance
        public static function get_instance()
        {
            // 判斷是否有初始化過
            if(is_null(self::$instance)) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        public function __construct()
        {
            $this->register_hooks();
            $order = wc_get_order(123);
        }

        /**
         * 註冊所有hooks
         */
        private function register_hooks()
        {
            // hook後面給的都是一個"可被呼叫的"的函式名稱,因為foo_bar是這個類別的方法,所以必須要傳入這個類別的實體(instance),才可在外部被呼叫,且foo_bar必須為public
            add_action('wp_head', [$this, 'foo_bar']);
        }

        public function foo_bar()
        {
            // do something
        }
    }
    // 在特定的hook時間點再初始化外掛
    // WooCommerce載入完之後會呼叫的action hook
    add_action('woocommerce_init', ['OctopusWP_Plugin', 'get_instance']); // 因為get_instance是static函式,所以只要給類別的名稱就行
    // 所有外掛都被載入完之後會呼叫的action hook
    add_action('plugins_loaded', ['OctopusWP_Plugin', 'get_instance']);
}

初始化的方法改成get_instance的方式,可以直接定義在類別內並傳入action hook

初始化的時機點也不是在外掛檔案被載入時馬上初始化,而是再hook到某一個action,在action被呼叫時再初始化

當然,如果你的外掛沒有任何依賴任何其他外掛,或者下列情形,就是直接初始化就好

// 判斷類別是否已經存在這個Class
if(!class_exists('OctopusWP_Plugin')) {
    class OctopusWP_Plugin
    {
        // 存放外掛類別的instance
        public static $instance;

        // 取得此類別的instance
        public static function get_instance()
        {
            // 判斷是否有初始化過
            if(is_null(self::$instance)) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        public function __construct()
        {
            $this->register_hooks();
        }

        /**
         * 註冊所有hooks
         */
        private function register_hooks()
        {
            // hook後面給的都是一個"可被呼叫的"的函式名稱,因為foo_bar是這個類別的方法,所以必須要傳入這個類別的實體(instance),才可在外部被呼叫,且foo_bar必須為public
            add_action('wp_head', [$this, 'foo_bar']);
        }

        public function foo_bar()
        {
            // do something

            // 雖然這裡有用到wc_get_order,但是foo_bar方法是在wp_head被呼叫時才會呼叫的,而這時WooCommerce已經被載入完畢了,所以不會出錯
            $order = wc_get_order(123);
        }
    }
    OctopusWP_Plugin::get_instance();
}

總之,這裡只要注意一下程式有載入順序,在外掛初始化時不能呼叫還沒被定義的方法或類別

但如果是在被hook的方法內,因在註冊hook時只會紀錄hook上去的方法資訊,在實際hook被呼叫時才會執行該方法


延伸閱讀:


此篇文章版權屬於OctopusWP

轉載請註明出處 @OctopusWP (https://www.octopuswp.com)

發佈留言

×

Cart