Welcart商品一覧ページで価格が高い・安い順に並び替え。二度手間なし一発データ取得

やりたいこと

Welcartの商品一覧ページは、デフォルトでは投稿日時の降順。新しく登録した順番に表示されます。(ワードプレスのデフォルトどおり)

この並び順を、閲覧者がドロップダウンリストで選択して変更できるようします。
選択項目は「新着順(デフォルト)」 「価格が安い順」 「価格が高い順」の3つ。

調べてみると既出の方法は、いずれも、並び替え用の価格を独自カスタムフィールドに保存するやり方でした。
Welcart が標準で持つSKUの価格情報とは別にです。
つまり、同じ価格を2回入力する必要があります。

メンテナンスが面倒ですし、間違いの素になるでしょう。

そこで、SKU情報から一発で価格データを取得して、その値で並び替えるようにしました。
二度手間をなくし、データ量とデータベースへの問合せを減らすことができます。

概要

  1. 商品一覧ページ(category.php)に並び替え条件を選択するselectボックスを設置
  2. select optionのvalueに移動先ページのURLを設定
  3. 選択optionが切り替わると、valueに設定されたURLをlocation.hrefに代入してページ移動させる
  4. 移動先ページでは、urlに付けられたクエリ文字列に応じて商品を並び替える
  5. 並び替えは、WP_Query 内部で発行されるSQL文のORDER BY句を直接変更することで行う
  6. 並び替える価格の値は、Welcart が標準で持つSKUデータからMySQL関数を使って一発で取得する

コード

category.php

selectボックスを設置します。
記載場所はwordpressループの開始直前。
if ( have_posts() )とwhile ( have_posts() )の間です。

使用するテーマによっては、記載ファイルがitem_category.phpの場合もあります。

if ( have_posts() ) :
	$sortset = (string)filter_input( INPUT_GET, 'sort' ); //$_GET['sort']の値を取得
?>
		<div class="">並び替え <!-- 送信しないのでformタグでなくてもOK -->

			<!-- 選択項目が切り替わるとそのvalue属性を読み取り、location.hrefに代入(ページ移動させる) -->
			<select name="item_sort" onChange="location.href=value;">
				<option value="<?php echo esc_url( add_query_arg( array( 'sort' => false ), get_pagenum_link() ) ); ?>"<?php if ( ! $sortset ) echo ' selected'; ?>>新着順</option>
				<option value="<?php echo esc_url( add_query_arg( array( 'sort' => 'price_asc' ), get_pagenum_link() ) ); ?>"<?php if ( $sortset && $sortset === 'price_asc' ) echo ' selected'; ?>>価格が安い順</option>
				<option value="<?php echo esc_url( add_query_arg( array( 'sort' => 'price_desc' ), get_pagenum_link() ) ); ?>"<?php if ( $sortset && $sortset === 'price_desc' ) echo ' selected'; ?>>価格が高い順</option>
			</select>
		</div>

		<div class="item-archive">
<?php
	while ( have_posts() ) : the_post(); //ループスタート

1番目のoptionはデフォルトで表示する新着順です。
add_query_arg()関数は、keyの値をfalseに設定するとURLにクエリ文字列が付きません。
デフォルトではURLパラメーターは付けないのでfalseにします。

functions.php

/**
 * フックのあるfile : wp-includes/class-wp-query.php
 * フックのあるfunction : get_posts

 * @param string $orderby ORDER BY句
 * @param WP_Query $query オブジェクト
 * @return string $orderby ORDER BY句
 */
add_filter( 'posts_orderby', function( $orderby, $query ) {
	if ( is_admin() || ! $query->is_main_query() ) {
		return $orderby; //デフォのORDER BY句をreturnしないとサブループ等で正しく並び替えできなくなる
	}

	//カテゴリーページの場合、ORDER BY句を変更する
	if ( $query->is_category() ) {
		global $wpdb;
		$sort = 'DESC'; //デフォの並び替えは降順(高い順)

		if ( isset( $_GET['sort'] ) ) { //urlパラメーターに?sort=があれば価格順に

			if ( $_GET['sort'] === 'price_asc' ) { //urlパラメーターがprice_ascなら
				$sort = 'ASC'; //昇順(安い順)に変更
			}

			//priceの値をピンポイントで取得してその値でORDER BY句を生成する
			$orderby = '(
				SUBSTRING_INDEX(
					SUBSTRING_INDEX(
						SUBSTRING(
							'. $wpdb->prefix. 'postmeta.meta_value,
							( INSTR(
								'. $wpdb->prefix. 'postmeta.meta_value,
								CONCAT( "\"", "price", "\";" )
								) + CHAR_LENGTH( "price" ) + 2
							)
						),
						"\"",
						2
					),
					"\"",
					-1
				) + 0
			) '. $sort; //$sortの値はurlパラメーターにより'DESC'or'ASC'可変

		} else { //urlパラメーターに?sort=がなければ
			$orderby = $wpdb->prefix. 'posts.post_date DESC'; //新着順(デフォルト)
		}
	}

	return $orderby;
}, 10, 2 );

27~41行目:SKUデータから価格の値だけをピンポイントで取得するSQL文です。
詳しい説明は次のページに投稿しています。
wordpressのシリアライズデータから目的の値をピンポイントで取得する(MySQL関数使用)

42行目:取得したpriceの値に+0を加算しているのは数値型に変換するため。
SUBSTRING_INDEX関数で取得した値は文字列型。
数値型にしないと数字で正しく並び替えされません。

ポイント

WP_Queryのパラメーターを設定する通常の方法では実現できない

Welcartの価格はsku情報に保存されています。
在庫数・在庫状態等と一緒に配列のシリアライズデータとしてです。

a:9:{s:4:"code";s:9:"WDP-CI-TE";s:4:"name";s:17:"チーク(TE)";s:6:"cprice";s:4:"2640";s:5:"price";s:4:"1500";s:4:"unit";s:0:"";s:8:"stocknum";s:3:"100";s:5:"stock";s:1:"0";s:2:"gp";s:1:"0";s:4:"sort";s:1:"0";}

保存場所はカスタムフィールド(postmetaテーブル)。
通常(値が単体)なら、WP_Queryのorderby, meta_key, meta_value等のパラメーターを設定することで並び替えできます。

ですが、上記データのように価格だけの単体データではないので、そのままでは並び替えできません。

posts_orderbyフィルターフックで並び替え条件を変更

WP_Queryの 内部で発行されるSQL文を直接変更する必要があります。
変更するのは並び替え。
なので、ORDER BY句に対するposts_orderbyフィルターフックを使って並び替え条件を書き換えます。

WelcartのSKUシリアライズデータからピンポイントで価格だけ取得

MySQLの関数を使います。
これによりピンポイントで価格の値を取得し、その値で並び替えできます。
wordpressのシリアライズデータから目的の値をピンポイントで取得する(MySQL関数使用)

add_query_arg()関数 でURLパラメーターを付与・削除

移動先ページのURLを取得するのはadd_query_arg()関数を使います。
URLにクエリ文字列を付けたり消したりする関数です。
関数リファレンス / add_query_arg – WordPress Codex 日本語版


コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です