WordPressの単一投稿ページや固定ページでは、<BODY>タグのクラスに投稿IDが出力されます。
単一投稿ページでは、class="single single-post postid-13 single-format-standard~"、固定ページでは、class="page page-id-68 page-template-default~"という形式で自動でクラス指定されるわけです1。
そして、アーカイブページのように複数の投稿をリスト化して表示するページの一つのリスト(テーマにより差はあるが、大抵は<ARTICLE>タグ)毎に、投稿IDがID属性とクラスに含まれています。
例えば、<article id="post-40" class="post-40 status-publish format-standard hentry"> という形式です。これはアーカイブページをはじめ、単一投稿ページや固定ページのメインコンテンツの記事部分も同様です。
基本的にこのデフォルトのタグ構造・クラス形式を継承するWordPressテーマであれば、単一投稿ページや固定ページが表示された時にその投稿IDをCookie等に保存することで、記事の既読判定を行うことが出来るようになります。
つまり、単一の投稿を表示した時点でその投稿IDをCookieの既読リストに保存して、アーカイブページや記事一覧系のコンテンツを表示するところでCookieから既読リストを読み出して照らし合わせることで、記事毎に未読・既読の表示を出し分けられるわけです。
では実践してみます。実際には出力されたHTMLを解析してのDOM処理となるため、WordPressテーマ等のPHPは全く触らずにJavaScriptオンリーで実現可能です。
まず、現在表示されているページの投稿IDを取得する関数を準備します。
function getPostID() {
// BODYタグのclass属性から投稿IDを取得する
var post_id = null;
var classList = $('body').attr('class').split(/s+/);
for (i=0; i<classList.length; i++) {
if (classList[i].indexOf('postid-') != -1) {
var post_id = Number(classList[i].replace('postid-', ''));
break;
} else if (classList[i].indexOf('page-id-') != -1) {
var post_id = Number(classList[i].replace('page-id-', ''));
break;
}
}
return post_id;
}
次に、Cookieのセッタとゲッタを定義します。
function setCookie(ck_name, ck_value, expiredays) {
// SetCookie
var path = '/';
var extime = new Date().getTime();
var cltime = new Date(extime + (60*60*24*1000*expiredays));
var exdate = cltime.toUTCString();
var pre_data = getCookie(ck_name);
var tmp_data = pre_data.split(',');
tmp_data.push(ck_value);
var fix_data = tmp_data.filter(function (x, i, self) { return self.indexOf(x) === i; });
var s = '';
s += ck_name + '=' + escape(fix_data.join(','));
s += '; path=' + path;
s += expiredays ? '; expires=' + exdate + '; ' : '; ';
document.cookie = s;
}
function getCookie(ck_name) {
// GetCookie
var st = '', ed = '', res = '';
if (document.cookie.length > 0) {
st = document.cookie.indexOf(ck_name + '=');
if (st != -1) {
st = st + ck_name.length + 1;
ed = document.cookie.indexOf(';', st);
if (ed == -1)
ed = document.cookie.length;
res = unescape(document.cookie.substring(st, ed));
}
}
return res;
}
以上が共通処理です。本項以下の処理を実行するために必要になります。
そして、単一投稿ページや固定ページなどの既読を判定させたい記事ページに下記のスクリプトを追加します。
function checkAlreadyRead() {
// 自ページのARTICLEタグの投稿IDを取得してCookieの既読済みリストと照らし合わせる
var match_already_read = false;
$('article').each(function() {
var pid = null;
var classList = $(this).attr('class').split(/s+/);
for (i=0; i<classList.length; i++) {
if (classList[i].indexOf('post-') != -1) {
var pid = Number(classList[i].replace('post-', ''));
break;
}
}
if (pid != '') {
var data = getCookie('already_read').split(',');
var post_ids = data.filter(function(x, i, self) { return self.indexOf(x) === i; });
post_ids.forEach(function() {
if (Number(arguments[0]) == pid) {
match_already_read = true;
}
});
// 既読済みARTICLEのclassにreadクラスを追加する
var add_class = match_already_read ? 'read' : '';
$(this).addClass(add_class);
}
});
return match_already_read;
}
var is_already_read = checkAlreadyRead();
$(window).scroll(function() {
// ヘッダーナビゲーションの高さ(例では60px)より下にスクロールしたら既読とする
if (!is_already_read) {
if ($(this).scrollTop() > 60) {
setCookie('already_read', getPostID(), 365);
is_already_read = true;
}
}
});
setTimeout(function() {
// このページへの滞在時間が2秒以上になったら既読とする
if (!is_already_read) {
setCookie('already_read', getPostID(), 365);
is_already_read = true;
}
}, 2000);
上記サンプルでは、そのページにて特定位置より下にスクロールするか、ページでの滞在時間が一定時間を超えた時のいずれかの条件で、既読フラグをONにし、Cookieに既読済みリスト「already_read」としてそのページの投稿IDを保存期間を365日(1年間)でセットしています2。
上記サンプルでは変数is_already_readを既読判定フラグとして定義してスイッチングしているだけで、特にこのフラグを使っての後続処理は行っていません。
例えば、既読判定フラグがTRUEになったら特定の処理をする関数を準備しておけば、下記のように呼び出すことができます。
// 呼び出し元
if (!is_already_read) {
setCookie('already_read', getPostID(), 365);
is_already_read = true;
setAlreadyReadIcon();
}
function setAlreadyReadIcon(){
// 既読クラス「read」を持つ要素の子要素に既読アイコンを追加する
$(document).find('.read').each(function() {
if (!$(this).children().is('.already-read-icon')) {
$(this).append('<div class="already-read-icon"><i class="fa fa-eye"></i></div>');
}
});
}
上記はあくまで一例ですが、本サイトのTOPページなどでは、既読の記事だったら記事ブロックの左下に既読アイコン(目のアイコン)を表示している処理を行っています。
※ 本項のスクリプトを動かすにはjQueryが必要です。
※ 既読リストはCookieに保存してあるため、ブラウザにてCookieを削除すると既読履歴がクリアされてしまいますのでご注意を。