プラグインなしで「お気に入り」機能を追加する方法(クッキー版)

Cocoonカスタマイズ集
この記事は約35分で読めます。
記事内に広告が含まれています。

参考:「新着情報」に「お気に入り」機能を追加する方法

Ajax方式で「新着情報」(info_listショートコ-ド)に「お気に入り」機能を追加します。

完成イメージ

使用方法

actionオプションを追加します。

[info_list action="favorite"]

実装手順

以下の手順で実装します。

  • ラベル
    PHPを追加

    以下のコードをfunctions.phpに追加します。

    // フロント用JS・CSSを追加
    add_action('wp_enqueue_scripts', function () {
      wp_enqueue_script('jquery-cookie', 'https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js', ['jquery'], '1.4.1', true);
    
      $ajax_url = admin_url('admin-ajax.php');
    
      ob_start();
      ?>
      jQuery(function ($) {
        var KEY = 'my_fav_page_list';
    
        /**
         * お気に入りボタンの状態を更新
         *
         * @return {void}
         */
        function syncUI() {
          // クッキーからデータを取得
          const currentCook = JSON.parse($.cookie(KEY) || '[]');
    
          $('.fav-button').each(function () {
            const id = String($(this).data('id'));
            $(this).toggleClass('active', currentCook.indexOf(id) > -1);
          });
        }
    
        /**
         * お気に入り一覧をAjaxで更新
         *
         * @return {void}
         */
        function refreshFavWidget() {
          const $favoriteArea = $('.favorite');
    
          if (!$favoriteArea.length) {
            return;
          }
    
          $.post('<?php echo esc_url($ajax_url); ?>', {
            action: 'refresh_fav_list'
          }, function (response) {
            if (!response) {
              return;
            }
    
            // DOMを差し替え
            $('.favorite').replaceWith(response);
            syncUI();
          });
        }
    
        // お気に入りボタンクリック
        $(document).on('click', '.fav-button', function (e) {
          e.preventDefault();
          e.stopPropagation();
    
          // クッキーからデータを取得
          const $btn = $(this);
          const id   = String($btn.data('id'));
          let cook   = JSON.parse($.cookie(KEY) || '[]');
          const index = cook.indexOf(id);
    
          // お気に入り状態を変更
          if (index > -1) {
            cook.splice(index, 1);
          } else {
            cook.push(id);
          }
    
          // クッキーを更新
          $.cookie(KEY, JSON.stringify(cook), { expires: 365, path: '/' });
    
          // お気に入り一覧の更新を通知
          $(document).trigger('favListUpdated');
        });
    
        // お気に入り一覧更新時に再描画
        $(document).on('favListUpdated', function () {
          syncUI();
          refreshFavWidget();
        });
    
        // クッキーの有効期限を更新
        const initialCook = JSON.parse($.cookie(KEY) || '[]');
    
        if (initialCook.length > 0) {
          $.cookie(KEY, JSON.stringify(initialCook), { expires: 365, path: '/' });
        }
    
        // 初回のボタン状態を確認
        syncUI();
      });
      <?php
      wp_add_inline_script('jquery-cookie', ob_get_clean(), 'after');
    });
    
    
    /**
     * Ajaxでお気に入り一覧を出力
     */
    if (!function_exists('ajax_refresh_fav_list')):
    function ajax_refresh_fav_list() {
      echo do_shortcode('[info_list action="favorite"]');
      wp_die();
    }
    endif;
    
    
    // Ajaxアクションを追加
    add_action('wp_ajax_refresh_fav_list', 'ajax_refresh_fav_list');
    add_action('wp_ajax_nopriv_refresh_fav_list', 'ajax_refresh_fav_list');
    
    
    // 新着情報の属性を設定
    add_filter('shortcode_atts_info_list', function ($out) {
      if (!session_id() && !headers_sent()) {
        session_start();
      }
    
      if (!isset($out['action']) || $out['action'] !== 'favorite') {
        return $out;
      }
    
      // 初回の設定をセッションに保存
      if (!wp_doing_ajax()) {
        $_SESSION['my_fav_page_list_atts'] = $out;
      }
      // Ajax再描画時に復元
      else if (wp_doing_ajax() && isset($_SESSION['my_fav_page_list_atts'])) {
        $out = $_SESSION['my_fav_page_list_atts'];
      }
    
      $GLOBALS['favorite'] = true;
      add_action('info_list_item_meta_before', 'get_fav_button');
    
      // 新着情報終了時に状態をリセット
      add_filter('get_info_list_tag', function ($tag) {
        $tag = '<div class="favorite">' . $tag . '</div>';
        $GLOBALS['favorite'] = false;
        remove_action('info_list_item_meta_before', 'get_fav_button');
    
        return $tag;
      });
    
      return $out;
    });
    
    
    // 新着情報のクエリを設定
    add_filter('get_info_list_args', function ($args) {
      if (empty($GLOBALS['favorite'])) {
        return $args;
      }
    
      $ids = [];
    
      // クッキーからお気に入りIDを取得
      if (isset($_COOKIE['my_fav_page_list'])) {
        $ids = json_decode(stripslashes($_COOKIE['my_fav_page_list']), true);
      }
    
      // お気に入り記事がない場合は終了
      if (empty($ids) || !is_array($ids)) {
        $args['post__in']       = [0];
        $args['posts_per_page'] = 0;
      } else {
        $ids = array_unique(array_map('intval', (array) $ids));
        $args['post__in'] = array_reverse($ids);
        $args['orderby'] = 'post__in';
      }
    
      $args['ignore_sticky_posts'] = true;
    
      return $args;
    });
    
    
    // テンプレート(エントリーカード)を変更
    add_filter('cocoon_part__tmp/entry-card', function ($content) {
      ob_start();
      get_fav_button();
      $button = ob_get_clean();
    
      return preg_replace('/(<h2[^>]*>)/', '$1' . $button, $content);
    });
    
    
    /**
     * お気に入りボタンを出力
     */
    if (!function_exists('get_fav_button')):
    function get_fav_button() {
      ?>
      <span class="fav-button" data-id="<?= get_the_ID(); ?>" title="お気に入り"><i class="fas fa-paperclip"></i></span>
      <?php
    }
    endif;
  • ラベル
    CSSを追加

    以下のコードをstyle.cssに追加します。

    :root {
      --fav-button-on : #ff0000;
      --fav-button-off: #ccc;
    }
    
    /* ボタン */
    .fav-button {
      cursor: pointer;
    }
    
    /* ボタン活性化 */
    .fav-button.active {
      color: var(--fav-button-on);
    }
    
    /* エントリーカード */
    .entry-card-title .fav-button {
      margin-right: 0.5em;
    }
    
    /* 新着情報 */
    .info-list-item {
      position: relative;
    }
    
    .info-list-item:has(.fav-button) .info-list-item-content{
      text-indent: 1.5em;
    }
    
    .info-list-item .fav-button {
      position: absolute;
      top: 14px;
    }

さいごに

今回の方法を使えば、プラグインを使わずに、ブラウザのクッキーを活用した独自の「お気に入り」機能を追加できます。
「新着記事」ウィジェットに「お気に入り」オプションを設け、ユーザーは任意の投稿をお気に入りとして登録・表示できるようになります。
この仕組みにより、ユーザーが興味のあるコンテンツに簡単にアクセスでき、利便性を向上させることが可能です。

タイトルとURLをコピーしました