いつもユニークなアイデアを紹介している宙也さんのサイト【ART+BEAT MANIFESTO】で、非常に興味深い記事を見つけたので、早速試してみました。
それは、サイト内の記事をお気に入りとして登録し、いつでも簡単にアクセスできるようにする機能です。通常、このような機能はプラグインを使って設置することが多いのですが、この記事ではプラグインを使わずに設置する方法が紹介されていました。
今回、設置するにあたり、少しカスタマイズを加えた点や、あるプラグインが原因で機能しないというトラブルへの対応方法も含め、備忘録として残しておこうと思います。
これから同じような機能の導入を検討している方に、少しでも参考になれば幸いです。
お気に入り機能の設置
この機能の設置については、宙也さんの下記記事をご参考ください。
PHP、Javascript、CSSをそのままコピーして追記すれば通常は問題なく機能します。
遭遇した問題点
宙也さんの記事に従って設置をしていき、問題なく機能しているようでしたが、落とし穴が…。
管理画面へログインをしたまま、サイトを表示して確認をしていると問題なく機能しているのですが、ログアウトし正規URLでアクセスすると機能していないことが判明。
いろいろと調べた結果、インストールしているプラグイン、WP Fastest Cache が問題を起こしていることが判明しました。
原因はクッキーがキャッシュされているために、機能していないようです。
ログイン時は、管理者なのでキャッシュはされないのですが、いったんログアウトするとキャッシュが邪魔をしてるようです。
解決方法は
解決方法は、WP Fastest Cache の設定で簡単に対処することが出来ました。
設定画面で ”除外する”のタブにある”クッキーを除外”に新しいルールを追加するだけです。
宙也さんの紹介されているのをそのまま使用するのであれば、”fav_page”を含むで作成すれば問題ないです。
上の画僧からも分かるように、管理者(Admin)はクッキーのキャッシュが除外されています。
これを見つけるまでに、丸1日かかってしまいました。
WP Fastest Cache や他のキャッシュプラグインを使っている方で、うまく作動しない場合はクッキーの設定を確認してみてください。
少しだけ自分好みに変更
お気に入り機能を設置するにあたり、少しだけ変更を加えさせていただきました。
主に、青い部分の変更と赤い部分の追記です。
内容は、
・ボタンをペンマークからクリップボードに変更
・ボタンの位置をタイトルの前から後ろに変更
・エントリーカードのタイトルの前または、説明文の後にボタンを追加
・ボタンへマウスオーバー時にメッセージ表示を追加(現在、宙也さんがCSSにて実装済みです)
共通コードの青いハイライト部分を変更していきます。
// jquery.cookieを追加
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script('cookie', 'https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js', ['jquery'], false, true);
});
// お気に入りボタンを追加
function get_fav_button() {
echo '<span class="fav-button" data-pageid="' . get_the_ID() . '"><i class="fas fa-pencil-alt"></i></span>';
}
// 投稿タイトル前にボタンを出力
add_filter('cocoon_part__tmp/content', function($content) {
ob_start();
get_fav_button();
$btn = ob_get_clean();
$content = preg_replace('/(<h1\s+class="entry-title".*?>)/', '$1' . $btn, $content);
return $content;
});
// クッキーからお気に入り投稿を取得
function modify_widget_args($args) {
global $action;
if ($action == 'favorite') {
$ids = [];
// Cookieから投稿履歴を取得
if (array_key_exists('fav_page', $_COOKIE)) {
$ids = json_decode($_COOKIE['fav_page']);
}
// 投稿IDが存在しない場合
if (empty($ids)) {
$args['post__in'] = [0]; // 無効なIDを指定して投稿を表示しない
$args['posts_per_page'] = 0; // 投稿を表示しない
} else {
$args['post__in'] = array_reverse($ids); // 最新順に並び替え
}
$args['ignore_sticky_posts'] = true; // 固定記事は表示しない
$args['orderby'] = 'post__in'; // 指定したID順にソート
}
$action = null;
return $args;
}
add_filter('widget_entries_args', 'modify_widget_args');
add_filter('get_info_list_args', 'modify_widget_args');
ボタンの変更
”fas fa-pencil-alt” ⇒ ”fas fa-clipboard-list”に変更
ボタンの位置をタイトルの前から後ろに変更
// 投稿タイトル後にボタンをスペース付きで出力
add_filter('cocoon_part__tmp/content', function($content) {
ob_start();
get_fav_button();
$btn = ob_get_clean();
$content = preg_replace('/(<h1\s+class="entry-title".*?>)(.*?)(<\/h1>)/', '$1$2 ' . $btn . '$3', $content);
return $content;
});
エントリーカードのタイトルの前または、説明文の後にボタンを追加
// エントリーカードの説明文の後にボタンを追加
function add_fav_button() {
// ボタンのHTMLを出力
get_fav_button();
}
add_action('entry_card_snippet_after', 'add_fav_button');
add_action('widget_entry_card_date_before', 'add_fav_button');
ボタンへマウスオーバー時にメッセージ表示を追加
// jQueryでマウスオーバー時にメッセージを表示する処理
add_action('wp_footer', function() {
?>
<script>
jQuery(document).ready(function($) {
// マウスオーバーイベント
$('.fav-button').on('mouseenter', function() {
var button = $(this);
var pageId = button.data('pageid');
var currentFavPages = $.cookie('fav_page') ? JSON.parse($.cookie('fav_page')) : [];
var message = button.hasClass('active') ? 'リストから削除' : 'ブックマークに追加';
// フローティングメッセージを表示
showMessage(message, button);
});
// メッセージ表示の関数
function showMessage(message, button) {
// 既存のメッセージ要素を削除
$('.fav-message').remove();
var msgDiv = $('<div class="fav-message">').text(message).appendTo('body');
var buttonOffset = button.offset();
msgDiv.css({
position: 'absolute',
top: buttonOffset.top - msgDiv.outerHeight() - 10, // ボタンの上に配置
left: buttonOffset.left, // ボタンの左端に合わせる
backgroundColor: '#f7ab00',
color: '#fff',
padding: '5px 10px',
borderRadius: '5px',
display: 'none',
zIndex: 9999 // 他の要素に隠れないようにする
}).fadeIn(300).delay(1000).fadeOut(300, function() {
$(this).remove();
});
}
});
</script>
<?php
});
共通コードへ変更を反映させたPHPが下記となります。
/***********************
お気に入り機能追加
***********************/
// jquery.cookieを追加
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script('cookie', 'https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js', ['jquery'], false, true);
});
// お気に入りボタンを追加
function get_fav_button() {
echo '<span class="fav-button" data-pageid="' . get_the_ID() . '"><i class="fas fa-clipboard-list"></i></span>';
}
// 投稿タイトル後にボタンをスペース付きで出力
add_filter('cocoon_part__tmp/content', function($content) {
ob_start();
get_fav_button();
$btn = ob_get_clean();
$content = preg_replace('/(<h1\s+class="entry-title".*?>)(.*?)(<\/h1>)/', '$1$2 ' . $btn . '$3', $content);
return $content;
});
// エントリーカードの説明文の後にボタンを追加
function add_fav_button() {
// ボタンのHTMLを出力
get_fav_button();
}
add_action('entry_card_snippet_after', 'add_fav_button');
add_action('widget_entry_card_date_before', 'add_fav_button');
// クッキーからお気に入り投稿を取得
function modify_widget_args($args) {
global $action;
if ($action == 'favorite') {
$ids = [];
// Cookieから投稿履歴を取得
if (array_key_exists('fav_page', $_COOKIE)) {
$ids = json_decode($_COOKIE['fav_page']);
}
// 投稿IDが存在しない場合
if (empty($ids)) {
$args['post__in'] = [0]; // 無効なIDを指定して投稿を表示しない
$args['posts_per_page'] = 0; // 投稿を表示しない
} else {
$args['post__in'] = array_reverse($ids); // 最新順に並び替え
}
$args['ignore_sticky_posts'] = true; // 固定記事は表示しない
$args['orderby'] = 'post__in'; // 指定したID順にソート
}
$action = null;
return $args;
}
add_filter('widget_entries_args', 'modify_widget_args');
add_filter('get_info_list_args', 'modify_widget_args');
// jQueryでマウスオーバー時にメッセージを表示する処理
add_action('wp_footer', function() {
?>
<script>
jQuery(document).ready(function($) {
// マウスオーバーイベント
$('.fav-button').on('mouseenter', function() {
var button = $(this);
var pageId = button.data('pageid');
var currentFavPages = $.cookie('fav_page') ? JSON.parse($.cookie('fav_page')) : [];
var message = button.hasClass('active') ? 'リストから削除' : 'ブックマークに追加';
// フローティングメッセージを表示
showMessage(message, button);
});
// メッセージ表示の関数
function showMessage(message, button) {
// 既存のメッセージ要素を削除
$('.fav-message').remove();
var msgDiv = $('<div class="fav-message">').text(message).appendTo('body');
var buttonOffset = button.offset();
msgDiv.css({
position: 'absolute',
top: buttonOffset.top - msgDiv.outerHeight() - 10, // ボタンの上に配置
left: buttonOffset.left, // ボタンの左端に合わせる
backgroundColor: '#f7ab00',
color: '#fff',
padding: '5px 10px',
borderRadius: '5px',
display: 'none',
zIndex: 9999 // 他の要素に隠れないようにする
}).fadeIn(300).delay(1000).fadeOut(300, function() {
$(this).remove();
});
}
});
</script>
<?php
});
ボタンへマウスオーバー時のメッセージに関するCSSもPHPから書き出しをしているので、宙也さんの掲載しているCSSは、ほぼそのまま使用しています。(1か所だけ数値を変更)
メッセージの変更は74行目となります。
また、88 ‐ 99行目がメッセージのデザインになります。
メッセージボックスのカラーなどはこちらを変更してください。
追記…カスタム投稿タイプに対応
お気に入り機能をカスタム投稿タイプでも機能するように下記を52行目に追記しました
青色の部分をカスタム投稿タイプ名に変更ください。
$args['post_type'] = ['post', 'news']; // デフォルト投稿とカスタム投稿タイプを含める
具体的には下の黄色いところに追加
$args['post_type'] = ['post', 'news']; // デフォルト投稿とカスタム投稿タイプを含める
$args['ignore_sticky_posts'] = true; // 固定記事は表示しない
$args['orderby'] = 'post__in'; // 指定したID順にソート
}
追記…新着情報 ウィジェットとショートコード
念のため、このブログで使用しているコードです。
宙也さんの記事の内容と同じだと思いますが、念のため記載しておきます。
// ショートコードでボタンを出力
add_filter('shortcode_atts_new_list', function($out) {
global $action;
if ($out['action'] == 'favorite') {
$action = 'favorite';
add_action('widget_entry_card_date_before', 'get_fav_button');
} else {
remove_action('widget_entry_card_date_before', 'get_fav_button');
}
return $out;
}, 10, 3);
使用する際のショートコード
[info_list action="favorite"]
新着情報 ウィジェットへのオプション追加コード
// ウィジェットに独自オプションを追加
add_filter('in_widget_form', function($widget, $return, $instance) {
if ($widget->id_base == 'info_list') {
$f_id = $widget->get_field_id('info_list');
$f_name = $widget->get_field_name('info_list');
$checked = checked(isset($instance['info_list']), true, false);
echo "<p><input type=\"checkbox\" class=\"widefat\" name=\"{$f_name}\" value=\"1\" {$checked}><label for=\"{$f_id}\">お気に入り</label></p>";
}
return $return;
}, 10, 3);
// メニューの値を更新
add_filter('widget_update_callback', function($instance, $new_instance, $old_instance, $this_widget) {
$instance['info_list'] = $new_instance['info_list'];
return $instance;
}, 10, 4);
// ウィジェットでボタンを出力
add_filter('widget_display_callback', function($instance, $widget, $args) {
global $action;
if ($widget->id_base == 'info_list' && isset($instance['info_list']) && !empty($instance['info_list'])) {
$action = 'favorite';
add_action('info_list_item_meta_before', 'get_fav_button');
}else {
remove_action('info_list_item_meta_before', 'get_fav_button');
}
return $instance;
}, 10, 3);
追記…新着記事 ウィジェットとショートコード
こちらも念のため、このブログで使用しているコードです。
宙也さんの記事の内容と同じだと思いますが、念のため記載しておきます。
// ショートコードでボタンを出力
add_filter('shortcode_atts_new_list', function($out) {
global $action;
if ($out['action'] == 'favorite') {
$action = 'favorite';
add_action('widget_entry_card_date_before', 'get_fav_button');
} else {
remove_action('widget_entry_card_date_before', 'get_fav_button');
}
return $out;
}, 10, 3);
使用する際のショートコード
[new_list action="favorite"]
新着記事 ウィジェットへのオプション追加コード
// ウィジェットに独自オプションを追加
add_filter('in_widget_form', function($widget, $return, $instance) {
if ($widget->id_base == 'new_entries') {
$f_id = $widget->get_field_id('fav_page');
$f_name = $widget->get_field_name('fav_page');
$checked = checked(isset($instance['fav_page']), true, false);
echo "<p><input type=\"checkbox\" class=\"widefat\" name=\"{$f_name}\" value=\"1\" {$checked}><label for=\"{$f_id}\">お気に入り</label></p>";
}
return $return;
}, 10, 3);
// メニューの値を更新
add_filter('widget_update_callback', function($instance, $new_instance, $old_instance, $this_widget) {
$instance['fav_page'] = $new_instance['fav_page'];
return $instance;
}, 10, 4);
// ウィジェットでボタンを出力
add_filter('widget_display_callback', function($instance, $widget, $args) {
global $action;
if ($widget->id_base == 'new_entries' && isset($instance['fav_page']) && !empty($instance['fav_page'])) {
$action = 'favorite';
add_action('widget_entry_card_date_before', 'get_fav_button');
}else {
remove_action('widget_entry_card_date_before', 'get_fav_button');
}
return $instance;
}, 10, 3);
詳しくは宙也さんの記事をご参考ください。
追記 CSSについて
宙也さんの方でボタンのメッセージ表示をCSSで実装するよう更新されていましたので更新前のCSSを下記に掲載させていただきました。
.fav-button.active {
color: #ff0000;
}
.info-list-item {
position: relative;
}
.new-entry-cards:has(.fav-button) .card-title,
.info-list:has(.fav-button) .info-list-item-content {
text-indent: 1.5em;
}
.new-entry-cards .fav-button,
.info-list .fav-button {
position: absolute;
top: 0;
}
青木部分を top: 14px; から top: 0;へ変更しボタンの位置をタイトルと同じ位置にしています。
Javascriptを1か所調整
メッセージを表示するにあたり、宙也さんのコードを青い部分の1か所だけ変更をしています。
$(function() {
var cook = [];
$('.fav-button').each(function() {
var id = $(this).data('pageid');
check_cookie(this, id);
// ボタンがクリックされた場合
$(this).on('click', function() {
// リンクへの伝搬を防止
event.stopPropagation();
event.preventDefault();
・
・
・
青い部分を下記に変更しました。
$(this).on('click', function(event) { // eventを引数として追加
とりあえずこれで終了です。
最後に、新着情報のウィジェットにオプション追加とショートコード用のPHPを追加しました。
さいごに
下記のようにお気に入り機能が設置できました。
お気に入り追加ボタンにメッセージを表示するようにしたものです。
メッセージは、”ブックマークに追加”と”リストから削除”が表示されます。
宙也さんのサイトで紹介されているカスタムはとても勉強になります。
いつも参考にさせていただき本当に助かります。感謝感謝です!
今回、少しだけ自分好みに変更した内容はChatGPTに頼りながらなんとか自分好みのデザインにすることができました。
お気に入り機能の設置を考えている方の少しでも参考になればと思います。
コメント