Elegant way to add parent categories?

Is there any more elegant way to automatically add the parent categories through PHP (not JavaScript) upon registering categories for a post from some custom page?

I Add the categories checked with the following code:

wp_set_post_terms($post_id, $catarray, 'category');

And then to automatically add the parent categories I have written this whole switch case that I often need to manually update… =S
Is there any more elegant way than the way here down below?

foreach ($catarray as $cat) {

    switch ($cat) {
        case "228": // アクセサリー
        case "226": // バッグ
        case "224": // 衣服
        case "231": // 帽子・スカーフ
        case "229": // ジュエリー
        case "262": // 雨具
        case "227": // 靴
        case "230": // 生地
        case "232": // 腕時計 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '225')"); //   Apparel & Accessories(アパレル&アクセサリー)
            break;

        case "252": // カー部品 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '251')"); // カー用品
            break;

        case "284": // 携帯電話・アクセサリー
        case "266": // 家電
        case "222": // オーディオ・映像装置
        case "221": // その他のデジタル製品 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '17')"); // デジタル製品&家電
            break;

        case "204": // 乾燥食品
        case "197": // 飲料品
        case "203": // 青果品
        case "206": // 肉類
        case "199": // 面類・米&小麦
        case "202": // ソース類
        case "201": // スパイス・調味料類
        case "200": // お菓子・スナック類
        case "205": // 野菜類 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '198')"); // 飲食料品
            break;

        case "218": // 浴槽製品
        case "220": // 家具
        case "216": // キッチン用具・食器
        case "219": // 伝統工芸品
        case "272": // 雑貨 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '217')"); // 家具・キッチン用具・食器
            break;

        case "254": // すべての農作製品 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '253')"); // 農作製品
            break;

        case "236": // アニメ製品
        case "237": // ギフト製品
        case "234": // 玩具 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '235')"); // ギフト・玩具・アニメ製品
            break;

        case "214": // 美容器具・製品
        case "208": // 化粧品
        case "211": // 香水
        case "212": // スキンケア製品
        case "213": // 石鹸・洗髪料
        case "210": // サプリメント・ビタミン 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '209')"); // 健康・美容製品
            break;

        case "250": // 工業製品
        case "248": // 建設資材
        case "247": // 床材
        case "264": // 水周り製品 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '249')"); // 工業・建設資材&製品
            break;

        case "269": // エネルギー・ソーラー
        case "245": // 照明 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '244')"); // 照明・エネルギー
            break;

        case "242": // 芸術品
        case "243": // 高級ステレオ 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '241')"); // 高級製品
            break;

        case "261": // 医療品・医薬品
        case "267": // 化学製品
        case "268": // 研究器具 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '260')"); // 医療品・化学製品・研究器具
            break;

        case "240": // オフィス用品
        case "263": // スクラッチカード
        case "169": // 文房具 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '238')"); // オフィス什器・文房具
            break;

        case "259": // スポーツ器具
        case "256": // スポーツウェア
        case "258": // 運動補助器具 
            $wpdb->query("INSERT INTO wp_term_relationships (object_id, term_taxonomy_id) VALUES ('".$post_id."', '257')"); // スポーツ関連
            break;
        default:
            break;
    }


}

2 Answers
2

wp_set_post_terms() uses wp_set_object_terms(). There is an action hook called set_object_terms which fires on successful setting of an object’s terms. The action hook looks like this

do_action ( 'set_object_terms', int $object_id, array $terms, array $tt_ids, string $taxonomy, bool $append, array $old_tt_ids )

What we can do here is, inside our action callback function, we can check whether the terms that we inserted is top level, and if not, we can get the parent ID’s from the term objects and then add the parent terms to the post object

You can try the following:

add_action( 'set_object_terms', function ( $object_id, $terms, $tt_ids, $taxonomy )
{
    // Lets make sure we run this only once
    remove_action( current_action(), __FUNCTION__ );

    // Lets only target the category taxonomy, if not, lets bail
    if ( 'category' !== $taxonomy ) 
        return;

    // Make sure we have terms to avoid bugs
    if ( !$tt_ids )
        return;

    // Get all the terms already assinged to the post-
    $post_terms = get_the_terms( $object_id, $taxonomy );

    if ( $post_terms ) {
        $post_term_ids = wp_list_pluck( $post_terms, 'term_id' );

        // Bail if $post_term_ids === $tt_ids
        if ( $post_term_ids === $tt_ids )
            return;
    }

    // We are busy with the category taxonomy, continue to execute
    $parent_ids = [];

    // Lets loop through the terms and get their parents
    foreach ( $tt_ids as $term ) {
        // Get the term object
        $term_object = get_term_by( 'id', $term, $taxonomy );
        // If top level term, just continue to the next one
        if ( 0 ===  $term_object->parent )
            continue;

        // Our term is not top level, save the parent term in an array
        $parent_ids[] = $term_object->parent;
    }

    // Make sure we have parent terms, if not, bail
    if ( !$parent_ids )
        return;

    // Make sure we do not have duplicate parent term ID's, if so, remove duplicates
    $parent_ids = array_unique( $parent_ids );

    // Make sure that our parent id's not in the $terms array, if so, remove them
    $parent_ids = array_diff( $parent_ids, $tt_ids );

    // Make sure we still have parent ID's left
    if ( !$parent_ids )
        return;

    // Lets add our parent terms to the object's other terms
    wp_set_object_terms( $object_id, $parent_ids, $taxonomy, true );

}, 10, 4 );

EDIT – Use-case

The above code goes into your functions.php and will automatically add the parent terms to the post if we pass any child terms to wp_set_object_terms().

Now, in your template, you can do the following

$child_cat_ids = [120]; // Array of child categories
wp_set_object_terms( 
    147,            // Post ID
    $child_cat_ids, // Array of child category ID's
    'category',     // Taxonomy the terms belongs to
    true            // Only append terms to existing ones
);

Note that you only need to worry about the child category you want to add to the post. As I said, the action above will take care to add the correct parent term to the post

Leave a Comment