ワイヤード・パンチ

元・大阪人が、岡山の山奥でも生きていけることを証明するためのブログ。

WordPressのプラグインでは、コアファイルをインクルードしてはいけない。

以前の記事で紹介したプラグインですが、このたびめでたく、WordPress公式のリポジトリで公開されることになりました。

しかし、プラグインの公開には審査が必要で、どのようなプラグインでも審査に通るわけではありません。

今回のプラグインも一度審査にひっかかってしまったのですが、その原因と対処方法をメモしておきます。

広告

審査が通らなかった原因。

作成したプラグインを申請する手順そのものは他のサイトで調べていただくとして、申請した翌日、公式から英文のメールが返ってきました。

それを読んでみると、どうやら審査に落ちてしまったようで、下記に示す内容を修正してほしいとのこと。

(一部のみ抜粋)

## Calling core loading files directly

Including wp-config.php, wp-blog-header.php, wp-load.php, or pretty much any other WordPress core file that you have to call directly via an include is not permitted.

These calls are prone to failure as not all WordPress installs have the exact same file structure. In addition it opens your plugin to security issues, as WordPress can be easily tricked into running code in an unauthenticated manner.

Your code should always exist in functions and be called by action hooks. This is true even if you need code to exist outside of WordPress. Code should only be accessible to people who are logged in and authorized, if it needs that kind of access. Your plugin’s pages should be called via the dashboard like all the other settings panels, and in that way, they’ll always have access to WordPress functions.

If you need to have a ‘page’ accessed directly by an external service, you should use query_vars and/or rewrite rules to create a virtual page which calls a function.

日本人なので、これじゃあ読めません。

google翻訳にかけて、ざっと直してみます。

## ##コアロードファイルを直接呼び出す

wp-config.php、wp-blog-header.php、wp-load.php、またはインクルード経由で直接呼び出さなければならない他のWordPressコアファイルを含めることは許可されていません。

これらの呼び出しは、すべてのWordPressのインストールがまったく同じファイル構造を持っているわけではないため、失敗する傾向があります。さらに、WordPressは認証されていない方法でコードを実行するように簡単に騙される可能性があるため、セキュリティ問題へのプラグインを開きます。

コードは常に関数内に存在し、アクションフックによって呼び出されるべきです。 WordPressの外にコードが存在する必要がある場合でも、これは当てはまります。そのような種類のアクセスが必要な場合は、ログインして許可されている人だけがコードにアクセスできるようにする必要があります。あなたのプラグインのページは、他のすべての設定パネルと同様にダッシュボードを介して呼び出される必要があります。そうすれば、WordPressの機能にいつでもアクセスできます。

外部サービスから直接アクセスできる ‘ページ’が必要な場合は、query_varsを使用したり、ルールを書き換えて関数を呼び出す仮想ページを作成する必要があります。

要するに、wp-load.phpなど、WordPressコアファイルをインクルードする処理を入れてはいけないということです。

問題となったコード。

どうして先程のような注意をされるような処理を入れたかというと、まず本プラグインはjavascriptでajax通信を行っており、そこからphpを呼び出しています。

そこからphpを呼び出した場合、通常ならばwp-load.phpをインクルードしないと、wordpress特有の関数が使えないからです。

まずはjavascript。

jQuery(function($) {
	ajax_url = $("input.ajax_url").val(); // ajax処理用phpのURL
	select_ids = $("input.select_id").val();
	select_ids = select_ids.split(',');
	$.ajax({
		type: "POST",
		url: ajax_url,
		data: {
			select_id: select_id
		}
	}).then(function(response) {
		// 成功時の処理
	}
});

続けて、ajax通信で呼び出されるphp。

require_once(dirname(dirname(dirname(dirname( __FILE__ )))) . '/wp-load.php');
require_once(dirname( __FILE__ ) . '/class.php');
$img_posts = new external_image_replace_get_posts();
echo $img_posts->replace_post();

(本記事のコードは一例です。実際のプラグインのコードとは異なります。)

だいたいの流れは、javascriptからselect_idという変数の値を渡したあと、phpでその値にもとづいて処理をしたあと、結果をjavascriptに返す、といった感じです。

なお、上記コードではphpにてクラスが書かれた別のphpを呼び出しており、そのphpの中でwordpress特有の関数を利用しています。

そのためにwp-load.phpが必要だったのですが、それができないとなると、どうすればいいのでしょうか。

解決方法。

javascriptに値を渡せる関数と、ajax通信専用のphpが用意されているので、それらを使うことになります。

まず、プラグインのphpに以下のコードを入れます。

add_action('admin_enqueue_scripts', 'external_image_replace_add_script');
function external_image_replace_add_script() {
	wp_enqueue_script("external_image_replace", "script.js");
	wp_localize_script( 'external_image_replace', 'external_image_replace_ajax', array( 'ajax_url' => admin_url('admin-ajax.php')) );
}

wp_localize_scriptという関数を使うことで、jsが起動されたときに、指定した値をjsに渡すことができます。

第1引数にはwp_enqueue_scriptで登録したjsのハンドル名と同じ名前を入れ、第2や第3引数で変数名と値を入れます。

上記コードの場合だと「external_image_replace_ajax.ajax_url = “admin-ajax.php”」という変数が使えるようになっています。

そして、「admin_url(‘admin-ajax.php’)」という値こそが、wordpress本体に組まれている、ajax通信に必須のphpというわけです。

javascriptのコードは以下のようになります。

jQuery(function($) {
	select_ids = $("input.select_id").val();
	select_ids = select_ids.split(',');
	$.ajax({
		type: "POST",
		url: external_image_replace_ajax.ajax_url,
		data: {
			action: 'external_image_replace',
			select_id: select_id
		}
	}).then(function(response) {
		// 成功時の処理
	}
});

ajax通信用にわざわざ新しいphpを用意していましたが、それは不要になりました。

代わりにadmin-ajax.phpが呼び出されます。

さらに、phpに渡す値として、「action: ‘external_image_replace’」という値が追加されています。

もう一度phpに戻り、下記のコードを追加します。

function external_image_replace_ajax() {
	require_once(dirname( __FILE__ ) . '/class.php');
	$img_posts = new external_image_replace_get_posts();
	echo $img_posts->replace_post();
	die(); // ajaxからの実行を終了させる際、これがないと最後に0が出力されてしまう。
}
add_action( "wp_ajax_external_image_replace" , "external_image_replace_ajax" );

「wp_ajax_○○」というアクションフックは、admin_ajax.phpにactionという変数を渡すと、その変数の値と○○が一致した場合に関数が実行されます

つまり今回の場合、ajaxによってadmin_ajax.phpにexternal_image_replaceが渡されると、処理が実行されます。

こうすることで、wp-load.phpをインクルードすることなく、wordpress特有の関数を利用したajax通信ができるというわけです。

なお、ajaxで行うphpの関数の最後には、「die()」を忘れずに付けましょう

そうしないと、なぜか最後に「0」と出力されてしまいます。

修正後の結果は?

wp-load.phpのインクルードをやめてadmin_ajax.phpを使う形に変え、審査落ちメールに修正後のプラグインがアップロードされているURLを返信メールに記載して、再審査をお願いしました。

(本当はメールに直接添付したかったのですが、gmailの仕様によりzipファイルは添付できないので、やむなく外部のアップローダーを使うことに。)

その結果、また翌日には英文のメールが返ってきて、見事に審査に合格、プラグインが公開されることになりました。

なお、結果のメールが来たからといってすぐに公開ではなく、SVNリポジトリにアップロードするなどの手順が必要になりますが、それらは各自で手順をご検索ください。

また、今回公開したプラグインは以下となります。

External image replace

プラグインの概要については、以前の記事をご覧ください。