WordPressのフックをもっとよく理解するために知っておきたいこと。
WordPress開発者にとって、フックは基本概念です。『もう開発で苦しまない!「フック」を理解したらWordPressは最強のCMSになる』では、フックとはなにか、その重要性、actionsとfiltersの2種類のフックがどのように動作するかコードサンプルで説明しました。また、静的および非静的クラスメソッドをactionsとfiltersにフックする方法を説明しました。
本記事では、インスタンス化されたクラス(オブジェクト)のメソッドをアクションとフィルターにフックする方法、名前空間のクラスメソッドをフックに統合する方法、WordPressのフックシステムでの名前空間の使用に対する注意事項、その解決方法を説明します。
オブジェクトメソッドをフックする
大規模なニュースサイトでニュースコンテンツに広告をシームレスに挿入するため、広告マネージャープラグインを構築するよう依頼されたと仮定します。以下に、その構築方法を説明します。
さまざまな広告ネットワークの広告コードを含む多数のメソッドがあるAdManagerクラスを作成します。
class AdManager {
/**
* AdSense unit code.
*/
public function adsense() { ?>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:inline-block;width:336px;height:280px"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="6762452247"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<?php }
/**
* Buysellads ad code.
*/
public function buysellads() {
// ...
}
}
Webサイトのテーマにはbefore_post_contentと呼ばれる、投稿コンテンツが表示される前に実行されるactionがあります。投稿コンテンツの前に広告を表示するためのadsenseメソッドをフックしたい場合は、どうすればよいでしょうか。
『カスタマイズを究めるためにもっと知りたいWordPressのフックのしくみ 』で解説したクラスのコンストラクタで実行する例とは異なり、次のようにクラスの外部にあるアクションへのフックを試みます。
public function __construct() {
add_action( 'before_post_content', array( $this, 'adsense' ) );
}
投稿コンテンツの前にGoogle AdSenseの広告を表示するため、クラスの外(おそらく使用中のWebサイトのテーマのfunctions.phpファイル内)でadsenseメソッドをbefore_post_contentアクションにフックするには、$thisをクラスのインスタンスと入れ替えます。
add_action( 'before_post_content', array( new AdManager(), 'adsense' ) );
そしてクラスのシングルトンインスタンスを返すメソッドがクラスに含まれることを伝えます。
class AdManager {
// ...
/**
* Singleton class instance.
*
* @return AdManager
*/
public static function get_instance() {
static $instance = null;
if ( $instance == null ) {
$instance = new self();
}
return $instance;
}
}
これはadsenseメソッドをbefore_post_contentアクションにフックする方法です。
add_action( 'before_post_content', array( AdManager::get_instance(), 'adsense' ) );
名前空間
WordPressのフックシステムは、WordPressに名前空間が存在していなかったころに開発されました。そのため、名前空間の関数やクラスメソッドをactionやfilterにフックするのは難しく感じるでしょう。
次のようにAdManagerクラスにSitePoint\Pluginの名前空間があることを伝えます。
namespace SitePoint\Plugin;
class AdManager {
// ...
}
before_post_contentアクションにAdManagerクラスのadsenseメソッドをフックするには、次のように名前空間のあるクラス名を付加します。
add_action( 'before_post_content', array( SitePoint\Plugin\AdManager::get_instance(), 'adsense' ) );
SitePoint\Plugin\による名前空間がある同じPHPファイル内にclassとadd_action関数の呼び出しがある場合は同じグローバル名前空間の適用を受けているので、クラス名への名前空間の付加は不要です。
クラスの例はこれで十分なので、今度はプレーン関数の説明をします。
wp_headアクションへフックするために、名前空間の関数があることを伝えます。
namespace SitePoint\Plugin;
function google_site_verification() {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
}
関数に付加した名前空間でフックする方法は次のとおりです。
add_action( 'wp_head', 'SitePoint\Plugin\google_site_verification' );
フックシステムと名前空間での恐怖体験
Admin Bar & Dashboard Access Control(管理バーとダッシュボードのアクセス制御)プラグインに、アンインストールするときプラグインオプションを削除するuninstall hookを登録しました。
次のコードのように簡単なものは、アンインストールの際に呼び出されるクラス名がPP_Admin_Bar_Controlでメソッドがon_uninstallの場合、問題にならないはずです。
register_uninstall_hook( __FILE__, array( 'PP_Admin_Bar_Control', 'on_uninstall' ) );
動作を確かめるため、プラグインオプションが削除されるか確認しようとプラグインのアンインストールを試みましたが、驚いたことに以下のエラーがありました。
The plugin generated 2137 characters of unexpected output during activation.
注意したいのは、クラスとregister_uninstall_hook関数がProfilePress\PP_Admin_Bar_Controlの名前空間においてどのように定義されているかです。
namespace ProfilePress\PP_Admin_Bar_Control;
register_uninstall_hook( __FILE__, array( 'PP_Admin_Bar_Control', 'on_uninstall' ) );
class PP_Admin_Bar_Control {
// ...
/** Callback to run when the uninstalled hook is called. */
public static function on_uninstall() {
if ( ! current_user_can( 'activate_plugins' ) ) {
return;
}
delete_option( 'abdc_options' );
}
// ...
}
プラグインがアンインストールされたときon_uninstallクラスメソッドがトリガーされない理由がわかりますか?
register_uninstall_hook関数は名前空間の下に定義されているので、クラスにも適用されるだろうと考えるかもしれませんが、そうではありません。動作させるには次のようなクラスに名前空間を付加する必要があります。
register_uninstall_hook( __FILE__, array( 'ProfilePress\PP_Admin_Bar_Control\PP_Admin_Bar_Control', 'on_uninstall' ) );
この問題を解決するのは実際大変でした。みなさんには同じストレスや頭痛を経験させたくないと思いました。
最後に
このような思いがけない問題は一部の開発者をうんざりさせWordPressから遠ざけます。WordPressがPHPにいまあるのような機能がない時代に開発されたことは忘れないほうがよいでしょう。私はいつもこのような問題を回避する方法を人びとに伝える努力をしています。WordPressのフックシステムを分かりやすく説明できたと願います。
(原文:Understanding Namespaces in the WordPress Hook System)
[翻訳:柴田理恵]
[編集:Livit]