WooCommerceショップでカテゴリ階層フィルタリングを修正する方法(DBを正規化)
親カテゴリでフィルターしても、製品が子カテゴリに割り当てられているにもかかわらず結果が表示されないという問題が発生している場合、このガイドが解決に役立ちます。
問題
症状: 親カテゴリでフィルターすると、子カテゴリに商品が存在する場合でも、商品が表示されません。
例:
- カテゴリ構造:
Federal Actions > SEC > Enforcement - 製品は次に関連付けられています:
Enforcement(子カテゴリのみ) - フィルタリング
Federal ActionsまたはSEC返します: 結果がありません - フィルタリング
Enforcement返します: 表示される製品
なぜこれが起こるのか
WordPress/WooCommerce 必要とする 製品は明示的にマークする必要があります すべての親カテゴリ 階層内、子カテゴリだけでなく。
WordPress 管理インターフェイスを介して子カテゴリに商品を割り当てる場合、WooCommerce は用語関係テーブルのすべての親カテゴリを自動的にマークしません。これは HUSKY の制限ではなく、データ構造の要件です。
正しいカテゴリ割り当てには、以下を含める必要があります。
- 子カテゴリ:
Enforcement - 親カテゴリー:
SEC - 親カテゴリ:
Federal Actions
この問題を確認する方法
- 商品編集ページに移動します:
wp-admin/post.php?post=YOUR_PRODUCT_ID&action=edit - 右側の[カテゴリ]メタボックスを確認する
- 確認してください すべての親カテゴリ 階層でチェックされます
- 子カテゴリのみがチェックされている場合 → この問題が発生しています
ソリューション:自動カテゴリ階層正規化
このソリューションは2つの部分で構成されています。
- 将来性のある修正: 商品保存時に親カテゴリを自動的にマークする
- 即時修正: すべての既存の商品を正規化します
パート 1: 親カテゴリの自動マーク (将来の製品)
このコードを子テーマの functions.php:
/**
* Automatically mark all parent categories when product is saved
* This ensures hierarchy filtering works correctly
*/
add_action('save_post_product', 'auto_mark_parent_categories', 10, 1);
function auto_mark_parent_categories($product_id) {
// Clear cache
clean_object_term_cache($product_id, 'product_cat');
// Get currently assigned categories
$terms = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'ids']);
if (!is_wp_error($terms) AND !empty($terms)) {
$all_terms = [];
// For each assigned category, get all its parents
foreach ($terms as $term_id) {
$all_terms[] = $term_id;
// Get all ancestor categories
$ancestors = get_ancestors($term_id, 'product_cat', 'taxonomy');
if (!empty($ancestors)) {
$all_terms = array_merge($all_terms, $ancestors);
}
}
// Assign product to all categories including parents
wp_set_object_terms($product_id, array_unique($all_terms), 'product_cat');
// Clear caches
clean_post_cache($product_id);
clean_object_term_cache($product_id, 'product_cat');
if (function_exists('wc_delete_product_transients')) {
wc_delete_product_transients($product_id);
}
}
}
これはどのように機能しますか:
- 製品が保存されるたびにトリガーされます
- 割り当てられているすべてのカテゴリを取得します
- 割り当てられた各カテゴリのすべての親カテゴリを検索します
- 製品に完全な階層マークを付けます
- 関連するすべてのキャッシュをクリアします
結果: 今後、保存されたすべての製品には、すべての親カテゴリが自動的に含まれます。
パート 2: 既存の製品を正規化 (ワンタイム修正)
このスクリプトは、データベース内のすべての既存の製品を修正します。これを追加してください 一時的 コードを functions.php:
/**
* One-time script to normalize all existing products
* Access: yourdomain.com/?normalize_cats=1 (must be logged in as admin)
*/
add_action('init', function () {
if (isset($_GET['normalize_cats']) AND current_user_can('manage_options')) {
$result = normalize_all_products_categories();
echo '<h2>Category Normalization Results</h2>';
echo '<pre>';
print_r($result);
echo '</pre>';
die();
}
});
function normalize_all_products_categories() {
global $wpdb;
// Get all product IDs
$args = [
'post_type' => 'product',
'post_status' => 'any',
'posts_per_page' => -1,
'fields' => 'ids'
];
$product_ids = get_posts($args);
$log = [];
$normalized_count = 0;
foreach ($product_ids as $product_id) {
// Get current categories
$terms = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'ids']);
if (!is_wp_error($terms) AND !empty($terms)) {
$all_terms = [];
// Collect all parent categories
foreach ($terms as $term_id) {
$all_terms[] = $term_id;
// Get ancestors
$ancestors = get_ancestors($term_id, 'product_cat', 'taxonomy');
if (!empty($ancestors)) {
$all_terms = array_merge($all_terms, $ancestors);
}
}
$all_terms = array_unique($all_terms);
// Only update if we're adding new parent categories
if (count($all_terms) > count($terms)) {
wp_set_object_terms($product_id, $all_terms, 'product_cat');
$normalized_count++;
$log[] = "Product #{$product_id}: added " . (count($all_terms) - count($terms)) . " parent categories";
}
}
}
// Log to WordPress error log
error_log("=== Category Normalization Complete ===");
error_log(implode("\n", $log));
error_log("Total normalized: {$normalized_count} products");
return [
'success' => true,
'normalized' => $normalized_count,
'total' => count($product_ids),
'details' => $log
];
}
使用方法:
- コードをあなたの
functions.php - 移動先:
https://yoursite.com/?normalize_cats=1(管理者としてログインしている必要があります) - スクリプトの完了を待機
- 更新された商品の数を示す結果が表示されます
- このコードを削除 一度実行した後
期待される出力:
Category Normalization Results
Array
(
[success] => 1
[normalized] => 156
[total] => 919
)
これは、919 件中 156 件の製品で親カテゴリが不足しており、修正されたことを意味します。
修正のテスト
両方の部分を実装した後:
- HUSKY フィルターがあるショップページに移動します
- でフィルタリングしてみてください 親カテゴリ
- 子カテゴリからの製品が表示されるはずです
- 階層をドリルダウンしてみてください – すべてのレベルが機能するはずです
なぜこれを HUSKY のデフォルトにしないのですか?
これはもっともな質問です。その理由は次のとおりです。
- データ構造の変更: これは WooCommerce のコアデータ関係を変更します
- ユニバーサルではない:一部のサイトでは、特定のビジネスロジックのために子カテゴリのみを意図的に割り当てています
- パフォーマンス: 非常に大きなカタログでは、すべての製品保存にオーバーヘッドが追加されます。
- Conflicts: カテゴリ間の関係を管理する他のプラグインと競合する可能性があります
Future Enhancement: これを オプション設定 HUSKY でユーザーが有効にできる場合、デフォルトの動作にはなりません。
代替案: 手動カテゴリ割り当て
手動制御を希望する場合は、次のことができます。
- 各製品の編集
- カテゴリーメタボックスで、チェック すべての関連する親カテゴリ 手動で
- 製品を保存
これは詳細な制御を提供しますが、大規模なカタログでは時間がかかります。
トラブルシューティング
スクリプトは0の正規化された製品を表示します。
- 製品にすでに正しい親カテゴリが割り当てられている可能性があります
- いくつかの商品を個別に確認して検証してください
正規化後もフィルタリングが機能しない
- すべてのキャッシュ(WordPress、サーバー、ブラウザ)をクリア
- HUSKYが正しいタクソノミーを使用していることを確認してください(
product_cat) - 他のフィルタープラグインとの競合を確認する
- 製品が公開されていることを確認 (ドラフトではない)
子カテゴリフィルターから製品が消える
これは起こらないはずですが、もし起こった場合は:
- このスクリプトは、既存のすべてのカテゴリ割り当てを保持します。
- 他のプラグインが干渉していないか確認してください
- バックアップから復元してサポートに連絡してください
カスタムタクソノミー
このソリューションは以下にも対応しています カスタムタクソノミー CPT UI または同様のプラグインで作成されました。単純に変更してください 'product_cat' カスタムタクソノミーのスラッグに:
// Example for custom taxonomy 'modality'
$terms = wp_get_post_terms($product_id, 'modality', ['fields' => 'ids']);
wp_set_object_terms($product_id, array_unique($all_terms), 'modality');
重要事項
- チャイルドテーマ必須: テーマの更新中にコードが失われるのを防ぐために、常に子テーマを使用してください
- まずバックアップを取ってください:正規化スクリプトを実行する前にデータベースをバックアップしてください
- ステージングでテストする: 可能であれば、まずステージングサイトでテストしてください。
- ワンタイムスクリプト: 実行後に正規化スクリプトを削除します
- Part 1 Code を維持:
save_post_productフックは永続的に残る必要があります
概要
functions.php に永続的に追加:
- 親カテゴリの自動マークフック(パート1)
一度実行して削除:
- 正規化スクリプト (パート 2)
期待される結果:
- 親カテゴリのフィルタリングは正しく機能する
- 子カテゴリのフィルタリングは引き続き機能します
- 階層ドリルダウンが正しく機能します
- 将来の製品は親カテゴリを自動的に含みます