WordPress+cookie+JavaScriptでお気に入り登録の機能を実装する

## はじめに
はじめまして。こんにちは。
初めて記事を書くので拙い文章で非常に読みにくいと思いますが、柔らかい優しい目で見て頂けると有り難いです。

今回WordPress(php)、Cookie、javascriptを使ってお気に入り登録ができる機能を実装しましたので、個人の備忘録としてまとめてみました。

調べていく中で、WordPressプラグイン「**WP Favorite Posts**」を使った実装のサイトが多かった為、プラグインを使わないやり方として、この内容での実装がどこかで誰かの役に立てればいいなと思っています。


## やりたいこと
![スクリーンショット 2024-05-26 22.54.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800808/94c5618c-e2e8-8b87-c339-0ecd47a0dd65.png)
![スクリーンショット 2024-05-26 22.54.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800808/ba76f071-75b6-8c90-9c9e-3cebaa1d237d.png)
気に入った商品をお気に入り登録すると一覧ページで確認することができ、削除もできる。
上記画像のようにお気に入り登録がされているか変化があると視覚的にもわかりやすい。

## 導入の流れ
1\.登録用のボタンの作成

html
```
<div class="p-main" data-pageid="<?php echo esc_attr(get_the_ID()); ?>">
    <!--
    現在の投稿やページのIDを取得
    esc_attr 関数はその値をHTML属性として安全にエスケープします。
    これは、IDが意図せずにHTMLやJavaScriptに影響を与えないようにするため。
    -->
    <div class="p-fav_button">
        <span class="__icon"></span>
    </div>
</div>
<div class="p-fav_button">
  <span class="__icon"></span>
</div>
</div>
```
css

```sass
.p-main
        .p-fav_button
          background-image: url(../images/common/heart_w.svg)
          background-size: contain
          background-repeat: no-repeat
          width: 28px
          height: 24px
        .p-fav_button.is-choosen
          background-image: url(../images/common/heart_b.svg)
          background-size: contain
          background-repeat: no-repeat
          width: 28px
          height: 25px
```

JavaScript

```javascript
jQuery(document).ready(function ($) {
  // ページ読み込み時にお気に入り登録済みかをチェック
  // checked_inspect関数で登録されているか
  checked_inspect()

  //  updateFavouriteItemsがお気に入り商品を取得して更新する関数
  function updateFavouriteItems() {
    $.ajax({
      //$ は jQueryの短縮形
      url: ajax_object.ajax_url, // WordPressのAJAX URL
      type: 'POST',
      data: {
        action: 'get_favourite_items', // このアクションがトリガーされるfunctions.phpに記述
      },
      success: function (response) {
        $('#list .p-list').html(response) // レスポンスをHTMLに挿入
        checked_inspect() //新しく取得した内容に対して、お気に入り登録済みかをチェックするための関数を再度呼び出している
      },
      error: function (xhr, status, error) {
        console.error('AJAX Error:', status, error)
        console.log(xhr.responseText) // サーバーからの応答をログに出力コンソールに出てくるように　リクエストが失敗した場合に実行される
      },
    })
  }

  // 初期読み込み時にお気に入り商品を更新
  updateFavouriteItems()

  // お気に入りボタンがクリックされたときの処理
  $(document).on('click', '.p-fav_button', function () {
    var fav = $.cookie('fav_item') ? JSON.parse($.cookie('fav_item')) : []
    var current_page_id = $(this).closest('.p-main').data('pageid')

    if (current_page_id) {
      var index = fav.indexOf(current_page_id)
      if (index > -1) {
        fav.splice(index, 1)
        $(this)
          .removeClass('is-choosen')
          .find('.__text')
          .text('お気に入りに追加')
      } else {
        fav.push(current_page_id)
        $(this)
          .addClass('is-choosen')
          .find('.__text')
          .text('お気に入りから削除')
      }
      var serializedArr = JSON.stringify(fav.filter(Boolean))
      $.cookie('fav_item', serializedArr, {
        expires: 7,
        path: '/',
        secure: location.protocol === 'https:',
      })
      console.log('Cookie set:', $.cookie('fav_item'))
      updateFavouriteItems() // クッキー更新後にお気に入り商品を更新
    }
  })

  // お気に入りから削除する関数
  window.removeFavourite = function (pageId) {
    var fav = $.cookie('fav_item')
      ? JSON.parse($.cookie('fav_item')).filter(Boolean)
      : []
    var index = fav.indexOf(pageId)
    if (index > -1) {
      fav.splice(index, 1)
      var serializedArr = JSON.stringify(fav) //更新されたお気に入りリストをJSON形式に変換してクッキーに保存
      $.cookie('fav_item', serializedArr, {
        expires: 7,
        path: '/',
        secure: location.protocol === 'https:',
      })
      console.log('Cookie updated:', $.cookie('fav_item'))
      updateFavouriteItems() // クッキー更新後にお気に入り商品を更新
    }
  }

  // ページ読み込み時にお気に入り登録済みかをチェックする関数
  function checked_inspect() {
    var fav = $.cookie('fav_item') ? JSON.parse($.cookie('fav_item')) : []
    //.p-main からページIDを取得
    $('.p-main').each(function () {
      var current_page_id = $(this).data('pageid')
      var button = $(this).find('.p-fav_button')
      if (fav.indexOf(current_page_id) > -1) {
        button.addClass('is-choosen').find('.__text').text('お気に入りから削除')
      } else {
        button
          .removeClass('is-choosen')
          .find('.__text')
          .text('お気に入りに追加')
      }
    })
  }
})
```

```php

data-pageid="<?php echo esc_attr($post_id); ?>">
```

上記記述にPHPの `echo esc_attr($post_id)` が使われており、 `$post_id` の値がエスケープされて出力されます。これにより、ページIDがHTML要素の data-pageid 属性に格納されます。
具体的には、$post_id はWordPressの投稿（またはページ）のIDを指しており、このIDが data-pageid 属性に設定されます。この属性を使うことで、JavaScriptやjQueryからこのIDにアクセスすることができます。
よって、一つひとつの商品にこの記述を入れることでどのページの商品もidで取得することができる。
（同じ商品でも重複して表示されることはない。）
![スクリーンショット 2024-06-10 9.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800808/ef910b69-bac4-310d-f91b-d5561337ae2e.png)
こんな感じでidが登録されていることは検証ツールで確認することができます。

### 注意点


開発環境で挙動はよくても本番環境に上げるとCookieの情報が反映されず、cookieの情報が失われてしまって、ここの原因を探るのに時間がかなりかかってしました。パスの設定を必ず入れる。
その記述を入れることを忘れない。



## 参考サイト
https://spreadsheep.net/wp-cookie/