WordPress でプラグインを開発するときに、ベタな関数だけで作っていくと、 関数名を重複しないようにするために長い関数名になりがちです。

そこで今回は、プラグインを クラス化することで関数をカプセル化してしまうことにします。

 

 

今回の記事は過去記事、

の続きになります。

 

プラグインで PHP の クラスを使ってみる

Photo by Kobu Agency on Unsplash

WordPress で簡単なプラグイン、特に関数が一つで済むようなものを開発している分にあまり感じないのかもしれませんが、複数の関数を使用してプラグインを組むと、どうしても関数名が重複するかどうか、というのは重大な関心事になります。

そんなときは、プラグインをクラスとして実装することをおすすめします。

 

関数でプラグインを作る場合

前回の記事では、ショートコードのプラグインで、そのショートコード使用している投稿を表示する場合にのみ、JavaScript や CSS を読み込むようにさせるようにしました。

前回のおさらいになりますが、関数のみで構成したプラグインのコードの大まかな流れは下のようになります。

// ショートコードの本体
function shortcode_func( $args, $content ) {
    // ショートコードの処理
}

// ショートコードを登録
add_shortcode( `shortcode_tag`, `shortcode_func`);

// スクリプト・スタイルシートの読み込みハンドラ
function register_func() {
    $page_id = get_the_ID();
    $option_id_array = get_option('shortcode_tag');
    if (in_array($page_id, $option_id_array)) {
    $plugin_url = plugin_dir_url( __FILE__ );
        wp_enqueue_style( 'my-plugin-style', $plugin_url . 'css/syle.css'  );
        wp_enqueue_script( 'my-plugin-script', $plugin_url . 'js/myplugin.js' );
    }
}

// スクリプト・スタイルシートの読み込みハンドラを登録
add_action( 'wp_enqueue_scripts', 'register_func' );

//
function save_option_shortcode_post_id_array( $post_id ) {
    if ( wp_is_post_revision( $post_id ) OR 'post' != get_post_type( $post_id )) {
        return;
    }
    $option_name = 'shortcode_tag';
    $id_array = find_shortcode_occurences($option_name);
    $autoload = 'yes';
    if (false == add_option($option_name, $id_array, '', $autoload)) {
        update_option($option_name, $id_array);
    }
}

//
function find_shortcode_occurences($shortcode, $post_type = 'post') {
    $found_ids = array();
    $args = array(
        'post_type'   => $post_type,
        'post_status' => 'publish',
        'posts_per_page' => -1,
    );
    $query_result = new WP_Query($args);
    foreach ($query_result->posts as $post) {
        if (false !== strpos($post->post_content, $shortcode)) {
            $found_ids[] = $post->ID;
        }
    }
    return $found_ids;
}

add_action('save_post', 'save_option_shortcode_post_id_array' );

プラグインをこのようにして作成すると、他のプラグインやテーマで使用されている関数名と重複しないようにするため、一意の(他と重複することのない)関数名を付ける必要があります。例えば、関数のプレフィックスをブログ名やテーマ名にしてみたり・・そうすると、自ずと関数名は長くなりがちです。

PHP のクラスを使用してプラグインを作ることで、そういった面倒なことからは開放されます。

 

プラグインを PHP のクラスで書いてみる

Photo by Caspar Camille Rubin on Unsplash

PHP でクラスをどのように書くかは他の情報をググっていただくとして、ここでは「Best Practices | Plugin Developer Handbook | WordPress Developer Resources」を参考にしてプラグインをクラスで書き換えてみたいと思います。

この参考記事の、「Architecture Patterns」の "Single plugin file, containing a class, instantiated object and optionally functions" を参考にして書き換えたのが以下になります。

class My_Plugin {
    static $instance = false;

    private function __construct() {
        // ショートコードを登録
        add_shortcode( 'shortcode_tag', array( $this, 'shortcode_func' ) );
        // スクリプト・スタイルシートの読み込みハンドラを登録
        add_action( 'wp_enqueue_scripts', array( $this, 'register_func' ) );
        add_action( 'save_post', array( $this, 'save_option_shortcode_post_id_array' )  );
    }

    // インスタンスを取得
    public static function getInstance() {
        if (! self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    // ショートコードの本体
    function shortcode_func( $args, $content ) {
        // ショートコードの処理
    }

    // スクリプト・スタイルシートの読み込みハンドラ
    function register_func() {
        $page_id = get_the_ID();
        $option_id_array = get_option('shortcode_tag');
        if (in_array($page_id, $option_id_array)) {
            $plugin_url = plugin_dir_url( __FILE__ );
            wp_enqueue_style( 'my-plugin-style', $plugin_url . 'css/syle.css'  );
            wp_enqueue_script( 'my-plugin-script', $plugin_url . 'js/myplugin.js' );
        }
    }

    // すべての投稿保存時に実行される関数
    function save_option_shortcode_post_id_array( $post_id ) {
        if ( wp_is_post_revision( $post_id ) OR 'post' != get_post_type( $post_id )) {
            return;
        }
        $option_name = 'shortcode_tag';
        $id_array = self::find_shortcode_occurences($option_name);
        $autoload = 'yes';
        if (false == add_option($option_name, $id_array, '', $autoload)) {
            update_option($option_name, $id_array);
        }
    }

    // 指定されたショートコードタグを含む投稿を配列で返す
    function find_shortcode_occurences($shortcode, $post_type = 'post') {
        $found_ids = array();
        $args = array(
            'post_type'   => $post_type,
            'post_status' => 'publish',
            'posts_per_page' => -1,
        );
        $query_result = new WP_Query($args);
        foreach ($query_result->posts as $post) {
            if (false !== strpos($post->post_content, $shortcode)) {
                $found_ids[] = $post->ID;
            }
        }
        return $found_ids;
    }
}

// クラスをインスタンス化
$My_Plugin = My_Plugin::getInstance();

 

WordPress でのプラグインのクラスはシングルトンがベター?

コードの最初の部分に注目すると、コンストラクタ __construct() が private で定義されているので、このクラスはそもそもクラスの外で new することができません。

// インスタンス変数
static $instance = false;

// コンストラクタ
private function __construct() {
    // ショートコードを登録
    add_shortcode( 'shortcode_tag', array( $this, 'shortcode_func' ) );
    // スクリプト・スタイルシートの読み込みハンドラを登録
    add_action( 'wp_enqueue_scripts', array( $this, 'register_func' ) );
    add_action( 'save_post', array( $this, 'save_option_shortcode_post_id_array' )  );
}

それではどうやってインスタンスの取得をするのかというと、それは getInstance() 関数を使用します。この関数では、$instancefalse であるときには、インスタンスを生成(new self())して $instance にセットし、返します。そうでなければ、(すでにインスタンスはセットされているので) $instance を返します。

// インスタンスを取得
public static function getInstance() {
    if (! self::$instance) {
        self::$instance = new self();
    }
    return self::$instance;
}

デザインパターンを学習されているとわかると思うのですが、これは典型的な「シングルトンパターン」で組まれていますね。生成されるインスタンスは一つで、そのインスタンスが使い回されるイメージです。

あと、ベタ書きとちがうのは、PHP の場合、クラス内の関数やフィールド変数の参照の際には、self:: をつけるということですね。最初このことを知らずに組んでいて、少し悩んでしまいました。

 

まとめ

プラグインをクラス化すると、クラス内部の関数名の命名について悩む必要がなくなります。

要するに、関数や変数が暮らす内部にカプセル化されるので、他のテーマやプラグインで使用されている関数と衝突することがありません。

もちろん、クラス名は他と重複しないようにする必要はありますが・・


 

 

zaturendo

中小企業社内SE。

0件のコメント

コメントを残す

アバタープレースホルダー

メールアドレスが公開されることはありません。 が付いている欄は必須項目です