Own products

  • 新規事業のアイディア創造機

Introduce

2016
11/15

同じ記事タイトルがすでに存在するか(=重複してるか)を調べてくれるWordPressプラグイン「Notify Duplicate Title」作りました!

この記事の読了時間:約1535

  • このエントリーをはてなブックマークに追加

このところ進めているクライアントワークのWordPress案件で、とあるカスタムポスト上で「すでに同じタイトルの記事があるかどうか」を知れたら良いなというご要望が浮上しまして。

そのカスタムポストってのが、例えて言うなら「人名辞典」とか「パーツ一覧」みたいな感じで、要は似たようなタイトルを持つ記事が多数収められる予定で、月数回くらい管理者さんが手入力で追加していくスタイル。

そうなると、何度も同じタイトル重複して投稿しちゃったりとか、このデータって入力したっけ?的なことになるのは確実だし、とはいえいちいち投稿前に検索するのも手間かかるし。。。

調べたら使えそうなプラグインがあったんだけど、作りが古く更新もされてないのと「投稿」にしか使えないってコトなので、、、作っちゃいました☆

その名も「Notify Duplicate Title」!

タイトルがかぶってたら(すでに存在していたら)画面上にアラート出すよ!っていうシンプルなWordPressプラグインです。

それではさっそく、使い方やら技術的なお話をば。

タイトルの重複を知らせるWordPressプラグイン「Notify Duplicate Title」

インストール方法・使い方

実はすでにWordPress公式ディレクトリに公開されているので、そこからzipを落として解凍→アップロードしてもいいし、WordPressの管理画面からプラグイン検索しても見つかるので、どちらでもお好きなようにインストールしてくださいな。

プラグイン自体は特に難しい設定も無いので、有効化するだけでOK!

インストールすると、新しくタイトルを書いたり、編集画面でタイトルが書き換えられたタイミングで(厳密には、タイトルのフォームからフォーカスが外れた時に)裏っ側で「同じポストタイプの中に同じタイトルの記事があるか」を検索、あるか無いかを画面上部に通知してくれます。

「Notify Duplicate Title」制作に関する技術について

今回の技術的ポイントは、何と言っても「WordPress管理画面でのAJAX処理」。

タイトルを記入するinputの値が変更された時に、非同期で検索→結果を受け取って即時表示する、という一連の流れを、WordPress内臓のAJAX機構とjQueryとPHPで実装した形となります。

順を追って処理の流れを見てみると

  • 1. タイトルを記入するinput(input id=”title”)の値が変更された時に…
  • 2. 「いま記入されたタイトルと同じタイトルの記事が、同じポストタイプの中にあるか」を調べて…
  • 3. あるなら「ある」無いなら「無い」という結果を返してもらって…
  • 4. その結果を受け取って、画面上部に通知を出す。

となりますね。

んで、上記1.はイベント監視、4.は即時表示ということでJavaScript(=jQuery)の担当箇所となり、2.の検索処理と3.の検索結果発表!はPHPで実装するという風になります。

[JS] 1. タイトルを記入するinput(input id=”title”)の値が変更された時に…

まずはプラグインの本体となるPHPファイル notify-duplicate-title.php と、前述1.と4.を行うJSファイル notify-duplicate-title.js を用意します。

このJSの処理が動いて欲しいのは、投稿やらポストタイプやらの「新規投稿」と「編集」の場面のみなので、手始めに本体PHPにてJSの出し分けをします。

PHP
function ndt_enqueue($hook_suffix){
	// post.php もしくは post-new.php の時に...
	if($hook_suffix === 'post.php' || $hook_suffix === 'post-new.php'){
		// notify-duplicate-title.jsと、ついでにjQueryも読み込んでね。
		wp_enqueue_script('notify_duplicate_title', plugins_url('js/notify-duplicate-title.js', __FILE__), array('jquery'));
		// おまじない1 ※あとで説明アリ
		wp_localize_script('notify_duplicate_title', 'NDT', array('endpoint' => admin_url('admin-ajax.php')));
	}
}
// 管理画面だったら上記関数を動かして!
add_action('admin_enqueue_scripts', 'ndt_enqueue');

これで不要なトコではプラグインが動かないというコトになりました。

んで続いてはJSファイルにて、jQueryを使ってタイトル記述箇所のイベントを監視しましょー。

JS
jQuery(document).ready(function($){
	$('#title').on('change', function(){
		// ここに処理が入る予定。
	});
});

現在のタイトルやポストタイプを条件として検索するためには、jQueryの$.ajax()なんかを使って「いま記入されたタイトル」と「いまのポストタイプ」をPHP側に渡してあげないといけません。

なので、次工程2.の前に「PHPでの検索に必要な値を、JSで渡してあげる」という処理が必要になります。

JS
jQuery(document).ready(function($){
	$('#title').on('change', function(){
		// 実際には記事IDも必要になるので取っとく。
		var post_id = $('#post_ID').val();
		var post_title = $('#title').val();
		var post_type = $('#post_type').val();

		$.ajax({
			url: ●●●●,
			data: {search_id: post_id, search_title: post_title, search_type: post_type},
			type: 'POST'
		}).done(function(response){
			// 通信が成功した場合の処理が入る予定。
		});
	});
});

さてさて「url: ●●●●」とありますが、検索に必要な値 post_title や post_type は、どこに渡してあげればいいでしょうか。

その答えこそ「WordPress内臓のAJAX機構」こと「admin-ajax.php」なのであります!

この「admin-ajax.php」を経由させることで、JSとPHPで簡単に値を受け取ったり渡したり、受け取ると同時に走らせたいPHPの関数を設定出来たりするのです!

なので、ここには admin-ajax.php へのパス(=admin_url(‘admin-ajax.php’);で取れる)を記述するんですが、JSファイル内だからPHP関数は直接使えない。。。

そこで現れるのが、さっきのPHPに記載した ※おまじない1、wp_localize_script()関数なんや!

PHP
wp_localize_script($handle, $name, $data);
// $handle
//    値を使用するJSのハンドル名
//    (wp_enqueue_scriptで定義した名前)
// $name
//    オブジェクト名を設定してね
//   (グローバルなオブジェクトになるのでユニークなヤツを)
// $data
//    渡す値
//    (配列形式でどうぞ)

このおまじないによって、PHP側で書かれた変数の値をJSに引き渡せるので、心置きなく admin_url(‘admin-ajax.php’) の値をJSに送ります。

JS
jQuery(document).ready(function($){
	$('#title').on('change', function(){
		var post_id = $('#post_ID').val();
		var post_title = $('#title').val();
		var post_type = $('#post_type').val();

		$.ajax({
			url: NDT.endpoint,
			data: {search_id: post_id, search_title: post_title, search_type: post_type},
			type: 'POST'
		}).done(function(response){
			// 通信が成功した場合の処理が入る予定。
		});
	});
});

これで NDT.endpoint の中には admin_url(‘admin-ajax.php’) の値が入ります。よかったですね。

[PHP] 2. 「いま記入されたタイトルと同じタイトルの記事が、いまのポストタイプの中にあるか」を調べて…

続いてはPHP側での検索処理。の前に、、、。

今回は検索結果を即時表示させたいので、ajax通信と同時に検索を行って結果を返すという流れにしなければいけません。

ここでadmin-ajax.phpの真骨頂!

admin-ajax.phpに渡す値に「action: ‘本体PHPで用意したアクションフック名’」という値を含めると、いざajax通信を行うって時にそのアクションフックを起動してくれるのです!

PHP
function duplicate_checker(){
	// ここに処理が入る予定。
}
// アクションフック名 wp_ajax_duplicate_title_checker
// 動かす関数 duplicate_checker
add_action('wp_ajax_duplicate_title_checker', 'duplicate_checker');
JS
jQuery(document).ready(function($){
	$('#title').on('change', function(){
		var post_id = $('#post_ID').val();
		var post_title = $('#title').val();
		var post_type = $('#post_type').val();

		$.ajax({
			url: NDT.endpoint,
			data: {
				search_id: post_id,
				search_title: post_title,
				search_type: post_type,
				// アクションフック名から「wp_ajax_」を抜いた文字列
				action: 'duplicate_title_checker'
			},
			type: 'POST'
		}).done(function(response){
			// 通信が成功した場合の処理が入る予定。
		});
	});
});

これでやっと、本体PHPにて検索処理が実装できます。よかったですね。

PHP
function duplicate_checker(){
	$search_id = $_POST['search_id'];
	$search_title = $_POST['search_title'];
	$search_type = $_POST['search_type'];

	$get_page_by_title_obj = get_page_by_title($search_title, OBJECT, $search_type);

	if($get_page_by_title_obj !== NULL && $get_page_by_title_obj->ID !== $search_id && $get_page_by_title_obj->post_title === $search_title) {
		// 重複してる場合の処理
	} else {
		// ユニークな場合の処理
	}
	exit;
}
add_action('wp_ajax_duplicate_title_checker', 'duplicate_checker');

get_page_by_title()はWordPressの関数で、タイトル文字列から記事があるか探してくれて、見つかったらその記事のオブジェクトを返すし、見つからなければNULLを返すってヤツ。

ただし大文字小文字の区別をつけてくれないので、そのへんはif文で対応するとして。

なので、NULLじゃない + 関数で取ってきた記事IDが自分自身じゃない + 関数で取ってきた記事のタイトル===検索対象タイトル = 重複しとるで!という切り分けをします。

[PHP] 3. あるなら「ある」無いなら「無い」という結果を返してもらって…

あるなしの結果はJSでこれ以上加工することもないので、OKのときは「<div id=”message” class=”notice notice-success”><p>ユニークですよ</p></div>」、重複してるときはエラーっぽく「<div id=”message” class=”notice notice-error”><p>重複してます</p></div>」というid/classを指定したHTMLを素直にechoで出力しちゃいます。

PHP
function duplicate_checker(){
	$search_id = $_POST['search_id'];
	$search_title = $_POST['search_title'];
	$search_type = $_POST['search_type'];

	$get_page_by_title_obj = get_page_by_title($search_title, OBJECT, $search_type);

	if($get_page_by_title_obj !== NULL && $get_page_by_title_obj->ID !== $search_id && $get_page_by_title_obj->post_title === $search_title) {
		echo '<div id="message" class="notice notice-error"><p>重複してます</p></div>';
	} else {
		echo '<div id="message" class="notice notice-success"><p>ユニークですよ</p></div>';
	}
	exit;
}
add_action('wp_ajax_duplicate_title_checker', 'duplicate_checker');

[JS] 4. その結果を受け取って、画面上部に通知を出す。

最後に、本体PHPでechoされた結果をそのまんまjQueryで吐き出します。

JS
jQuery(document).ready(function($){
	$('#title').on('change', function(){
		var post_id = $('#post_ID').val();
		var post_title = $('#title').val();
		var post_type = $('#post_type').val();

		$.ajax({
			url: NDT.endpoint,
			data: {
				search_id: post_id,
				search_title: post_title,
				search_type: post_type,
				action: 'duplicate_title_checker'
			},
			type: 'POST'
		}).done(function(response){
			$('#message').remove();
			$('#poststuff').prepend(response);
		});
	});
});

あとはセキュリティのためにsanitize系の関数を使ったりnonce使ったりして、無事完成と相成りました!

というワケで、ご利用の機会がありましたら、ぜひとも!!

Notify Duplicate Title

めっちゃ久々の公式ディレクトリ申請だったから、subversionとかさっぱり。。

でも仕事の合間の良い息抜きになった!

年末進行に向けて、ファイトっ!!

  • このエントリーをはてなブックマークに追加

コメントを投稿する

お名前

ご連絡先メールアドレス※非公開

コメント

CAPTCHA


  • このブログのRSSを購読する
  • このブログをtwitterでつぶやく
  • このブログをFacebookで共有する
  • このブログをはてなブックマークで共有する

Favorite feeds

    Contact

    お名前※必須

    ご連絡先メールアドレス

    お問い合わせ内容※必須

    CAPTCHA

    captcha

    Blog parts

    Affiliate