🔧

WooCommerceで商品並べ替えのカスタマイズをする

2024/05/12に公開

この記事について

WooCommerceでの構築・カスタマイズのお仕事を最近よく受けています。
その中で商品アーカイブページの並べ替え機能をカスタマイズをする必要性が生じ、具体的なケースも含めて備忘録として残したいと思います。

使用するフックの簡単な特徴なども併せて書いていこうと思いますので、カスタマイズの際の参考になれば嬉しいです。

本記事の対象者

WordPressのフックでのカスタマイズを理解している
WordPressのWP_Queryを扱える
WordPressのデータベースの大まかな構造を把握している

並べ替え名称の変更・追加・削除

商品の投稿日の新しい順:「新しい順に並び替え」($sortby['date'])
価格の安い順:「価格順:安い 高い」($sortby['price'])
価格の高い順:「価格順:高い 安い」($sortby['price-desc'])

…と、WooCommerceの標準で用意されている並べ替え名称はそのままだとちょっと分かりにくいので変更したい・不要な並べ替え項目は削除したい・独自の並べ替え項目を追加したい…
そんな時には、以下の2つのフィルターフックを使用します。

  • woocommerce_default_catalog_orderby_options
  • woocommerce_catalog_orderby

具体的なケースがこちら。

function custom_sort($sortby)
{
  // 名称変更
  $sortby['date'] = '新着順';
  $sortby['price'] = '価格が安い順';
  $sortby['price-desc'] = '価格が高い順';

  // 項目追加
  $sortby['new-price-asc'] = '在庫量+安い順';
  $sortby['stock'] = '在庫量順';

  // 項目削除
  unset($sortby['popularity']); // 人気順:商品売上順
  unset($sortby['rating']); // 平均評価順:レビュー有効時、評価の良い順
  return $sortby;
}
add_filter('woocommerce_default_catalog_orderby_options', 'custom_sort');
add_filter('woocommerce_catalog_orderby', 'custom_sort');

名称変更の場合は、例のように新しく名称になって欲しい文字列を入力すると上書きされます。
項目追加は$sortbyのキーとなるアルファベット名称(stock)と名称の文字列(在庫量順)を記述すればOKです。

削除はunset()で要素削除すれば消えてくれます。

※補足
項目追加の際、キーの名称を'price-asc'としたら$sortby['price']と同じ並び順が適用されました。

WooCommerceの商品並べ替えの考え方の基本

至ってシンプルですが、WooCommerceの商品一覧関連の処理はWP_Queryでの処理です。
もっと言うと、post_typeをproductに絞ったWP_Queryの処理ということになります。

並べ方の編集(orderby/order/meta_key)

既存の並べ替え・自分で新しく追加した並べ替えについて、orderby・order・meta_keyの編集で並べ方をカスタマイズできるフックがあります。
それがwoocommerce_get_catalog_ordering_argsです。

具体例を見ていきましょう。

function edit_sort($args) {
  $orderby_value = isset($_GET['orderby']) ? wc_clean($_GET['orderby']) : apply_filters('woocommerce_default_catalog_orderby', get_option('woocommerce_default_catalog_orderby'));
    if ('new-price-asc' == $orderby_value) { // 新しい
      $args['orderby'] = ['stock' => 'desc', 'price' => 'asc', 'regular_price' => 'asc']; // 別のフックでmeta_queryを設定する
    } elseif ('stock' == $orderby_value) { // 在庫量順の設定
      $args['orderby'] = ['meta_value_num' => 'desc', 'date' => 'desc'];
      $args['meta_key'] = '_stock';
    }

    return $args;
}
add_filter('woocommerce_get_catalog_ordering_args', 'edit_sort');

'new-price-asc'の方は、以下の条件で並べ替えを設定します。

  • 優先度1:在庫量が多い順
  • 優先度2:セール価格が安い順
  • 優先度3:標準価格が安い順

データベースのwp_postmetaには次の箇所にデータが保存されています。

  • 在庫量 = _stock
  • セール価格 = _price
  • 標準価格 = _regular_price

そのため、これらを基準にして並べ替えしたいので、後程紹介する別のmeta_query追加用フックで使う予定のkeyの名前をそれぞれstock・price・regular_priceとして、昇順か降順かを連想配列の形で登録します。

後半では、在庫量順の設定をしています。
在庫量順はorderbyとmeta_keyを編集すれば良いだけなので、このフックのみで実装が完了します。

このフックは、最初からある並べ替えのorderbyの内容の上書きにも使えます。

function edit_sort($args) {
  $orderby_value = isset($_GET['orderby']) ? wc_clean($_GET['orderby']) : apply_filters('woocommerce_default_catalog_orderby', get_option('woocommerce_default_catalog_orderby'));
    if ('date' == $orderby_value) {
      $args['order'] = 'asc';
    }

    return $args;
}
add_filter('woocommerce_get_catalog_ordering_args', 'edit_sort');

上のようにすると、既存の「新しい順に並び替え」が古い順になります。
orderが初期値のdescからascに変えたためですね。

並べ方の編集(meta_query)

さて、在庫量と価格を基準にした'new-price-asc'の並べ替えにはmeta_queryの登録が必要になるという状況でした。
meta_queryの追加にはwoocommerce_product_query_meta_queryというフックを使います。

具体例はこちら。

function add_new_price_asc( $meta_query, $query ) {
  if ( !is_admin() ) {
    // URLパラメータで並べ替えを検知
    $url = '';
    $url .= isset($_SERVER['HTTPS']) ? 'https://' : 'http://'; 
    $url .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    $url_param = parse_url($url, PHP_URL_QUERY);
    if ( ( is_shop() || is_product_category() || is_product_tag() ) && $url_param === 'orderby=new-price-asc' ) ) {
      $meta_query[] = [
        'relation' => 'AND',
        'stock' => [
          'key' => '_stock',
          'type' => 'NUMERIC'
        ],
        'price' => [
          'key' => '_price',
          'type' => 'NUMERIC'
        ],
        'regular_price' => [
          'key' => '_regular_price',
          'type' => 'NUMERIC'
        ]
      ];
    }
  }
  return $meta_query;
}
add_filter( 'woocommerce_product_query_meta_query', 'add_new_price_asc', 10, 2 );

どこのページでmeta_queryを追加してほしいのか、条件を書いています。
今回は、管理画面以外+並べ替えが表示されるアーカイブ関連ページ+この並べ替えが選択された際にURLパラメータが付与されることを利用して、そのパラメータを条件分岐に使いました。

relationをANDにした後、'stock','price','regular_price'という名前を付けたデータが入っています。
これがwoocommerce_get_catalog_ordering_argsで、後で使うと書いたorderbyのキー名です。
全てtypeはNUMERICとして、数値で並べ替え参照するようにします。
こうすることで、並べ替え時にmeta_queryが追記されて機能するようになります。

今回は並べ替えに使いましたが、meta_queryなので条件抽出のクエリも書くことができます。

その他、使えるフックの紹介

本記事では詳しくご紹介しませんが…tax_queryを追記できるwoocommerce_product_query_tax_queryというフックも存在します。
書き方はwoocommerce_product_query_meta_queryと同じ感じです。

また、アクションフックでwoocommerce_product_queryというフックがあります。
これでmeta_queryやtax_query以外の主な項目をクエリに追加することもできます。

function custom_stock_query($query) {
  if($query->query_vars['orderby'] == 'stock') {
    $query->set('orderby', ['meta_value_num' => 'desc', 'date' => 'desc']);
    $query->set('meta_key', '_stock');
  }
}
add_action( 'woocommerce_product_query', 'custom_stock_query');

上のような記述で、woocommerce_get_catalog_ordering_argsの時に対応した在庫量順のorderbyとmeta_keyの追加をすることもできます。(動作確認済み)

個人的にwoocommerce_get_catalog_ordering_argsフックの方が使いやすいかなと思います。

woocommerce_product_queryで上手く機能しなかったパターンもあって、確証はまだないのですが…挙動を見るにorderbyでmeta_queryを介して複数のフィールド参照で並べ替えするためにキー名を設定する方法が原因で機能しない感じでした。

もし詳しい理由が分かりましたら、追記したいと思います。
この点で、原因について知見のある方のコメントをお待ちしております。

最後に

これらのフックを利用すると、自分で作成した商品用カスタムフィールドの値を参照して並べ替えることも可能なので、独自の並べ替え方法を提供することもできるようになります。
以上、参考になりましたら幸いです。

Discussion