work.log

エンジニアの備忘録的ブログ

WordPressでカテゴリとタグを使った入れ子メニューを表示する

投稿:2014-04-22 16:52  更新:

WordPress でカテゴリとタグを使った入れ子メニューを表示するメモ書き。

以前に、カテゴリとタグで絞り込める検索フォームを作ったのはいいですが、ぶっちゃけドロップダウンメニューって見難いよねってことでコレを改造して入れ子型のメニューリストを作ってみたいと思います。

完成はこんな感じです。

twentyfourteen-customize-009-01

では早速コードから。

functions.php にベタ書きするか、このコードを nestmenu.php みたな別ファイルに切り出して functions.php に include してやる。今回は見通しの良さを考慮して後者を採用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<?php
 
function nestmenu( $args ) {
 
    $nestmenu = '';
 
    if ( ! isset( $args['exclude'] ) ) {
        $args['exclude'] = '';
    }
 
    $opt = array(
        'hide_empty'   => true,
        'exclude_tree' => $args['exclude']
    );
 
    $cat_array = get_categories( $opt );
 
    $nestmenu  = "<div id='nestmenu'>\n";
    $nestmenu .= "<ul class='nestmenu-category'>\n";
 
    foreach ( $cat_array as $key => $cat ) {
 
        $cat_name = $cat->name;
        $cat_num = $cat->count;
        $cat_link = get_category_link( $cat->term_id );
        $tag_array = nestmenu_relation($cat->term_id);
 
        $nestmenu .= "<li><h2><a href='$cat_link' title='$cat_name'>$cat_name ($cat_num)</a></h2></li>\n";
        $nestmenu .= "<ul class='nestmenu-tag'>\n";
 
        foreach ( $tag_array as $tags ) {
 
            foreach ( $tags as $tag ) {
 
                $tag_link = esc_url( home_url( '/' ) . '?cat=' . $cat->term_id . '&tag=' . $tag['slug'] );
                $nestmenu .= "<li><a href='$tag_link' title='$tag[name]'>$tag[name] ($tag[count])</a></li>";
 
            }
 
        }
 
        $nestmenu .= "</ul>\n";
 
    }
 
    $nestmenu .= "</ul>\n";
    $nestmenu .= "</div>\n";
 
    return $nestmenu;
 
}
add_shortcode( 'nestmenu', 'nestmenu' );
add_filter( 'widget_text', 'do_shortcode' );
 
function nestmenu_relation( $term_id = false ) {
 
    if ( $term_id === false ) {
        return $term_ids;
    }
 
    $taxonomy = get_terms(
        array(
            'category',
            'post_tag'
        ),
        array(
            'hide_empty' => true,
            'include'    => $term_id
        )
    );
 
    $taxonomy = $taxonomy[0]->taxonomy;
 
    if ( ! is_null( $taxonomy ) ) {
 
        $args = array(
            'nopaging'            => 1,
            'ignore_sticky_posts' => 1,
            'order'               => 'ASK',
            'tax_query'           => array(
                array(
                    'taxonomy' => $taxonomy,
                    'terms'    => $term_id,
                    'field'    => 'id',
                    'operator' => 'AND'
                 )
            )
        );
 
        $my_query = new WP_Query( $args );
 
        if( $my_query->have_posts() ) {
 
            if ( $taxonomy === 'category' ) {
                $taxonomy = 'post_tag';
            } else {
                $taxonomy = 'category';
            }
 
            while ( $my_query->have_posts() ) : $my_query->the_post();
 
                $term = get_the_terms( get_the_ID(), $taxonomy );
 
                if ( $term ) {
 
                    foreach ( $term as $value ) {
 
                        if ( ! isset( $term_ids['term'][$value->term_id] ) ) {
 
                            $term_info = array(
                                'id'   => $value->term_id,
                                'name' => $value->name,
                                'slug' => $value->slug,
                            );
 
                            $term_ids['term'][$value->term_id] = $term_info;
 
                        }
 
                        $term_ids['term'][$value->term_id]['count'] += 1;
 
                    }
 
                }
 
            endwhile;
 
            wp_reset_query();
 
        }
 
        if ( $term_ids['term'] ) {
 
            $term_ids['term'] = array_merge( $term_ids['term'] );
 
            foreach ( $term_ids['term'] as $key => $value ) {
                $key_id[$key] = $value['count'];
            }
            array_multisort( $key_id, SORT_DESC, $term_ids['term'] );
 
        }
 
    }
 
    return $term_ids;
}
 
?>

※ 関数名 nestmenu, nestmenu_relation が他とぶつかる場合は適時修正する。
※ 子カテゴリ等を使ってる場合等は動作未検証。

この入れ子メニューは下記のショートコードで呼び出せるので、テキストウィジェットに貼り付けて表示させます。

[[nestmenu]]

除外したいカテゴリがある場合は下記のように exclude にカテゴリ ID を指定。

[[nestmenu exclude=”1,10,100″]]

こんなイメージで入れ子メニューが表示されます。

  1. 全カテゴリの一覧を取得しループ (除外は除く)
  2. カテゴリに含まれるタグを取得 (投稿が 1 以上あるもの)
  3. アンカータグをつけてリスト表示

css は #nestmenu (全体を囲む div), .nestmenu-category (カテゴリの ul), .nestmenu-tag (タグの ul) 辺りを利用して調整する。

このブログはこんな感じの css でサイドウィジェットに表示しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* nestmenu */
#nestmenu h2 {
    font-size: 14px;
    margin-top: 8px;
    margin-bottom: 8px;
    border-bottom: 1px dotted #dcdcdc;
}
 
#nestmenu ul {
    list-style: none;
}
 
#nestmenu .nestmenu-category {
    margin-left: 0;
}
 
#nestmenu .nestmenu-tag {
    margin-left: 13px;
}
 
#nestmenu .nestmenu-tag li {
    font-size: 13px;
}

カテゴリ、タグが沢山ある場合は、アコーディオン式のメニューにした方が見やすいかもしれないです。

簡単ですが、カテゴリとタグを使った入れ子メニューの表示はこれで以上です。

スポンサーリンク

コメント

  1. みぃ より:

    こちらとっても参考になりました。
    ありがとうございます。

    1点

    Warning: Invalid argument supplied for foreach() in nestmenu.php on line 31

    というエラーがでてしまったのですが、
    こちらの対処方法はわかりますでしょうか?

    何から何まで質問で申し訳ございません。

    • miura より:

      みぃ様

      ご質問いただいた件、以下に回答します。

      1. エラーについて

      空の配列をループさせようとした時に出るエラーですね。

      このプログラムは投稿記事に必ず、カテゴリとタグが設定されている事を想定して作った物なので、細かいエラー処理を入れていないのですがもしかするとそこが原因かもですね。

      だいぶ前に作った物なので自分でも色々と失念していますが、恐らく、WordPress の使い方によってはエラーが起きてしまうのかなとも思います。

      申し訳ありませんがこれはサンプルプログラムとしていただいて、実動作については個別で修正等の対応をしていただければと思います。

      2. 任意の件数分だけタグを表示

      別スレッドで頂いた件も合わせて回答します。

      「任意の件数分」というのは、例えば、記事に設定された回数が多い順にタグを10個表示とかでしょうか。

      勿論可能ですけど、これはカスタマイズ次第だと思います。

      サンプルプログラムを改変するなりして、この要件を満たすように別途プログラミングする必要があると思います。

      • みぃ より:

        色々とありがとうございました!

        こちらのコードを色々カスタマイズしてみようと思います。

コメントを残す

よく読まれている記事

  • 今日
  • 週間
  • 月間