a-blog cmsでサイト独自の「いいね！」機能を構築する

この記事は、[a-blog cms Advent Calendar 2018](https://adventar.org/calendars/2948) の13日目の記事です。

![likepreview.gif](https://qiita-image-store.s3.amazonaws.com/0/100753/cc1a727f-b5b2-aa18-53d5-1252c0bd6e27.gif)

通常記事詳細ページにはFacebookやTwitterなどのSNSボタンを設置しますが、SNSアカウントがないサイト訪問者向けにサイト独自に「いいね！」ボタンを設置したいことがあるかと思います。本稿では少々踏み込んだ内容になりますが、カスタマイズの事例として、サイト独自の「いいね！」ボタンを実装する方法をご紹介します。（WordPressでいうところの[WP ULike](https://wordpress.org/plugins/wp-ulike/)のようなものです）
※データベースを変更する内容が含まれているので、ご利用の場合は自己責任でお願いいたします。

# 実装の流れ

1. a-blog cmsが適用されない領域を作る
2. a-blog cmsが適用されない領域に「いいね！」ボタン用のphpを設置
3. テーマの entry.html に「いいね！」ボタンの雛形を設置
4. 「いいね！」ボタン用のphpと、entry.htmlに設置した「いいね！」ボタンの雛形を連携

# 1. a-blog cmsが適用されない領域を作る

まずa-blog cms領域直下にある、.htaccessでa-blog cmsが適用されないディレクトリを作成します。今回は、/system/ 以下をa-blog cmsが適用されないディレクトリにします。

## 修正前

```/.htaccess
# a-blog cms以外のコンテンツ（a-blog cmsを動作させないディレクトリ）
# RewriteCond %{REQUEST_URI} !^/?other/
# RewriteCond %{REQUEST_URI} !^/?other2/
```

## 修正後

```/.htaccess
# a-blog cms以外のコンテンツ（a-blog cmsを動作させないディレクトリ）
RewriteCond %{REQUEST_URI} !^/?system/?
```

# 2. a-blog cmsが適用されない領域に「いいね！」ボタン用のphpを設置

`/system/like/?mode=get&eid=1` のようなリクエストを送れば数値を返す、 `/system/like/?mode=put&eid=1` のようなリクエストを送ればカウントアップして数値を返す（cookieで1度クリックすると1年間再度クリックできない）phpプログラムを組みます。eidでどの記事の「いいね！」が押されたか特定します。


```/system/like/index.php
<?php
/**
 * いいね！ボタン
 * /system/like/?mode=get&eid=1
 * /system/like/?mode=put&eid=1
 */

	require_once('../../config.server.php');
	$dsn = 'mysql:dbname='.DB_NAME.';host='.DB_HOST.';charset=utf8';
	$pdo = new PDO($dsn, DB_USER, DB_PASS);

	// テーブルがなければ新規制作
	$sql = "CREATE TABLE IF NOT EXISTS `like_table`
		(
			`id` INT PRIMARY KEY AUTO_INCREMENT,
			`entry_id` INT,
			`account_id` VARCHAR(255),
			`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
		);";
	$stmt = $pdo -> prepare($sql);
	$stmt -> execute();

	// パラメータ受取
	$mode   = filter_input(INPUT_GET, 'mode');
	$eid    = filter_input(INPUT_GET, 'eid');
	$userid = filter_input(INPUT_COOKIE, 'userid');

	// Cookieがなければ発行
	if( !$userid ){
		$ticket = md5(uniqid(mt_rand(), true));
		$expire = time() + ( 60 * 60 * 24 * 365 ); //1年間間保持
 		setcookie('userid', $ticket, $expire, '/');
 		$userid = $ticket;
	}

	// 表示処理
	if( $mode == 'get' && $eid ){
		$stmt = $pdo->prepare("SELECT COUNT(*) FROM `like_table` WHERE `entry_id` = ?");
		$stmt->execute([$eid]);
		echo $stmt->fetchColumn();
	}

	// 追加処理
	if( $mode == 'put' && $eid && $userid ){
		// 投票済みでないかチェック
		$stmt = $pdo->prepare("SELECT COUNT(*) FROM `like_table` WHERE `entry_id` = ? AND `account_id` = ?");
		$stmt->execute([$eid, $userid]);
		// 投票済みでなければ投票
		if( $stmt->fetchColumn() == 0 ){
			$stmt = $pdo->prepare("INSERT INTO `like_table` (`entry_id`, `account_id`) VALUES (?, ?)");
			$stmt->execute([$eid, $userid]);
		}
		// 数値を返す
		$stmt = $pdo->prepare("SELECT COUNT(*) FROM `like_table` WHERE `entry_id` = ?");
		$stmt->execute([$eid]);
		echo $stmt->fetchColumn();
	}

?>
```

# 3. テーマの entry.html に「いいね！」ボタンを設置

entry.htmlに「いいね！」ボタンの雛形を設置します。どの記事の「いいね！」が押されたか特定するため、`data-vote-entry-id="%{EID}"` でエントリーIDを特定します。

```/themes/*****/entry.html
<!-- BEGIN_MODULE Entry_Body -->
<!-- BEGIN entry:loop -->
<div class="vote" id="vote">
  <p class="vote-lead">この記事が気に入ったら「いいね！」ボタンを押してください</p>
  <a href="#" class="vote-button" data-vote-entry-id="%{EID}">
    <span class="icon"><i class="fa fa-heart"></i>いいね!</span>
    <span class="number"></span>
  </a>
</div>
<!-- END entry:loop -->
<!-- END_MODULE Entry_Body -->
```

# 4.「いいね！」ボタン用のphpと、entry.htmlに設置した「いいね！」ボタンの雛形を連携

下準備が整ったので2で作成したphpと、3で作成したentry.htmlをJavaScriptで連携させます。ページを開いたら「いいね！」ボタンが表示されるよう、下記のJavaScriptをサイトに組み込みます。/system/like/index.php に対して、表示の場合はmodeにget、クリックされた場合はmodeにput、eidは記事のIDのパラメータを渡します。

```/themes/*****/js/common.js
$(document).ready(function(){
	$('.vote-button').each(function(){
		var $vote = $(this);
		// 表示処理
		$.ajax({
			type: 'GET',
			url: '/system/like/',
			cache: false,
			data: {
				'mode': 'get',
				'eid': $vote.data('vote-entry-id')
			},
			success: function(data){
				$vote.find('.number').text(data);
			}
		});
		// 追加処理
		$vote.click(function(){
			$.ajax({
				type: 'POST',
				url: '/system/like/',
				cache: false,
				data: {
					'mode': 'put',
					'eid': $vote.data('vote-entry-id')
				},
				success: function(data){
					$vote.find('.number').text(data);
				}
			});
			return(false);
		});
	});
});
```

# 動作確認

これで「いいね！」ボタンは完成です。このように記事のIDを使うことで様々なシステムとの連携が可能です。Good / Badボタンにしたり、「どのくらい役に立ちましたか？」などで1～5段階にしたり、もう一度「いいね！」したら「いいね！」を取り消すなどの応用も可能です。同様の仕組みで、[a-blog cmsでクイックアンケート機能を構築する](https://qiita.com/shinobu03/items/2843426ff7faf56f5ad3)方法もまとめましたのでぜひご覧ください。