ランキングの表示を評価順に並び替える方法

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

はじめに

以下の質問に回答します。

「ランキング」ウィジェットでは、Cocoon設定→ランキングから各アイテムの表示順を手動で上下に移動させて順位を決めます。
そのため、評価数が多いアイテムが必ずしも上位に表示されるわけではありません。

もし評価数順に自動で並べ替えたい場合、アイテム数が増えると手作業での並べ替えは大きな負担になります。

そこで、各アイテムの評価値に基づき、自動的に順位を並び替えて表示するようにします。

この記事では、この方法について説明します。

実装手順

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

add_filter('cocoon_get_item_ranking', function ($record, $id) {
  // 対象外の場合は終了
  if (empty($record) || is_admin()) {
    return $record;
  }

  // 評価を基準に設定
  uasort($record->item_ranking, function ($a, $b) {
    $ra = (isset($a['rating']) && $a['rating'] !== 'none') ? floatval($a['rating']) : 0;
    $rb = (isset($b['rating']) && $b['rating'] !== 'none') ? floatval($b['rating']) : 0;

    // 両方とも評価なしの場合は順序を維持
    if ($ra === 0.0 && $rb === 0.0) {
      return 0;
    }

    // aの評価なしを後ろへ移動
    if ($ra === 0.0) {
      return 1;
    }

    // bの評価なしを後ろへ移動
    if ($rb === 0.0) {
      return -1;
    }

    // 評価の高い順に変更
    return $rb <=> $ra;
  });

  // 配列のキーを変更
  $record->item_ranking = array_values($record->item_ranking);
  
  // 1始まりの形式に設定
  array_unshift($record->item_ranking, null);

  return $record;
}, 10, 2);

補足

設定値は、wp_optionsテーブルのオプション名cocoon_ranking_custom_settingsに、以下の形式で保存されます。

[
  62 => 1,  // ランキングID 62 は ソートON
  65 => 0,  // ランキングID 65 は ソートOFF
]

拡張:ウィジェットに「ソート」オプションを追加する方法

「ランキング」ウィジェットに「ソート」オプションを追加します。

完成イメージ

実装手順

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

$GLOBALS['ranking_widget'] = null;


// ウィジェットに設定メニューを追加
add_action('in_widget_form', function ($widget, $return, $instance) {
  // アイテムランキングウィジェット以外の場合は処理を終了
  if ($widget->id_base !== 'item_ranking') {
    return;
  }

  // 設定値とフィールド情報を取得
  $sort_by_rating = isset($instance['sort_by_rating']) ? (bool) $instance['sort_by_rating'] : false;
  $field_id = $widget->get_field_id('sort_by_rating');
  $field_name = $widget->get_field_name('sort_by_rating');
  ?>
  <p>
    <input type="checkbox" id="<?= esc_attr($field_id); ?>" name="<?= esc_attr($field_name); ?>" value="1" <?php checked($sort_by_rating); ?> />
    <label for="<?= esc_attr($field_id); ?>">
      評価の高い順にソートして表示
    </label>
  </p>
  <?php
}, 10, 3);


// ウィジェットの入力データを更新
add_filter('widget_update_callback', function ($instance, $new_instance, $old_instance, $widget) {
  // アイテムランキングウィジェット以外の場合はそのまま返す
  if ($widget->id_base !== 'item_ranking') {
    return $instance;
  }

  // ソート設定を登録
  $instance['sort_by_rating'] = !empty($new_instance['sort_by_rating']) ? 1 : 0;

  return $instance;
}, 10, 4);


// フロントエンド表示に反映
add_filter('widget_display_callback', function ($instance, $widget, $args) {
  // アイテムランキングウィジェットの場合のみインスタンスを格納する
  if ($widget->id_base === 'item_ranking') {
    $GLOBALS['ranking_widget'] = $instance;
  }

  return $instance;
}, 10, 3);


// ランキングデータ取得時に評価順へ変更
add_filter('cocoon_get_item_ranking', function ($record, $id) {
  // 対象外は終了
  if (empty($record) || is_admin()) {
    return $record;
  }

  // ウィジェット設定を取得
  $current_instance = $GLOBALS['ranking_widget'] ?? null;

  // 対象外は終了
  if (
    empty($current_instance) ||
    !isset($current_instance['ranking_id']) ||
    intval($current_instance['ranking_id']) !== intval($id) ||
    empty($current_instance['sort_by_rating'])
  ) {
    return $record;
  }

  // 評価を基準に変更
  uasort($record->item_ranking, function ($a, $b) {
    $ra = (isset($a['rating']) && $a['rating'] !== 'none') ? floatval($a['rating']) : 0;
    $rb = (isset($b['rating']) && $b['rating'] !== 'none') ? floatval($b['rating']) : 0;

    // 両方とも評価なしは順序を維持
    if ($ra === 0.0 && $rb === 0.0) {
      return 0;
    }

    // aの評価なしを後方へ変更
    if ($ra === 0.0) {
      return 1;
    }

    // bの評価なしを後方へ変更
    if ($rb === 0.0) {
      return -1;
    }

    // 評価の高い順に変更
    return $rb <=> $ra;
  });

  // 配列のキーを変更
  $record->item_ranking = array_values($record->item_ranking);
  
  // 1始まりの形式に設定
  array_unshift($record->item_ranking, null);

  return $record;
}, 10, 2);
タイトルとURLをコピーしました