【Cocoon】アーカイブウィジェットを年別にまとめてコンパクト表示【カスタマイズ】

WordPress
スポンサーリンク

WordPressの標準機能であるアーカイブウィジェットをカスタマイズしました。

備忘録として残しておきます。

変更前→変更後のデザイン

アーカイブウィジェットは設定でドロップダウン表示とリスト表示が選べますが、そのままのデザインではしっくりきませんでした。

それぞれのカスタマイズ前のデザインです。

ドロップダウン表示

ドロップダウン表示はちょっと味気ないデザインだし、月を選択するのに2クリックしなければならないので操作性も悪いなと感じていました。

リスト表示

一方のリスト表示。
これぐらいの長さならまだ問題ありませんが、これから長年サイトを運用していくとなると、もっと長さも伸び、見栄えや操作性も悪くなります。

なので今回は、

  • 一覧性がある(分かりやすさ)
  • 1クリックで飛べる(使いやすさ)
  • コンパクトな表示(見やすさ)

この三点を目標にカスタマイズした結果、

完成形

こんな感じのデザインになりました。

直近の年は最初から表示、それ以外の年はスペース節約のため非表示になっています。
各年をクリックすると表示・非表示を切り替えできます。

今回のカスタマイズはCocoonの作者、わいひらさんの記事を参考にさせてもらいました↓

折り畳み式アーカイブウィジェットを作成するWordPressカスタマイズ方法。プラグイン不要コピペのみ。
今回は、Wordpressアーカイブウィジェットのリスト表示を、プラグインを必要とせず、コピペのみでスッキリと…

ウィジェットの設定

まずはウィジェットの設定を確認します。

「外観」→「ウィジェット」で、アーカイブをクリックし「ドロップダウン表示」のチェックを外して保存。

ここにチェックしたままだとドロップダウン表示になります。

CSSのソースコード

以下のコードを、「外観」→「テーマエディター」Cocoon Childのstyle.cssに貼り付けます。

/*---折り畳みアーカイブウィジェット---*/
.widget_archive a.year{ /*各年*/
	cursor: pointer;
	border-bottom: 1px dotted #ccc; /*各年に下線を引く*/
}
.widget_archive a.year::after{ /*各年横のアイコン*/
	font-family: "Font Awesome 5 Free";
	content: '\f107'; /* アイコンの指定 */
	position: relative; /* 相対配置 */
	left: 5px; /* アイコンの位置 */
	font-weight: bold;
}
.widget_archive .years ul { /*各月*/
	display: flex;
	flex-flow: row wrap;
	margin-left: 5px; /*インデント*/
	font-size: 1rem;
	text-decoration: underline; /*各月に下線を引く*/
}
.widget_archive ul.years li {
	padding: 0 1px; /*各月の間隔*/
}
#sidebar .widget_archive ul.years li :hover { /*マウスホバー時*/
	background: none;
	transition: 0.1s;
	color: #72c7e6;
}
.widget_archive ul.years .hide { /*各年をクリックすると開閉*/
	margin: 0;
	height: 0;
	opacity: 0;
	visibility: hidden;
	overflow: hidden;
}

6〜11行目のコードは「Font Awesome5」に設定している場合です。
「Font Awesome4」に設定している場合は対応するコードに変えてください。

Font Awesomeについては↓の記事が分かりやすかったです。

【Cocoon】Font Awesome 4から5へ変更する前に注意すべきこと
2019年11月14日に無料WordPressテーマ「Cocoon」のバージョンが2.0.0になり、多くのブロックエディター機能が強化されました。そして今回のアップデートでFont Awesome 5が漸く公式から使用できるように用意されま...

jQueryのソースコード

次に、以下のjQueryコードをCocoon Childのjavascript.jsに貼り付けます。

///////////////////////////////////
// 折り畳み式アーカイブウィジェット
/////////////////////////////////
(function($) {
  $(function() {
    var wgts = $(".widget_archive");//アーカイブウィジェット全てを取得
    //アーカイブウィジェットを1つずつ処理する
    wgts.each(function(i, el) {
      wgt = $(el);

      //日付表示+投稿数か
      var has_date_count = wgt.text().match(/\d+年\d+月\s\(\d+\)/);
      //日付表示だけか
      var has_date_only = wgt.text().match(/\d+年\d+月/) && !has_date_count;

      //日付表示されているとき(ドロップダウン表示でない時)
      if ( has_date_count || has_date_only ) {
        var
          clone = wgt.clone(),//アーカイブウィジェットの複製を作成
          year = [];
        //クローンはウィジェットが後に挿入。クローンはcssで非表示
        wgt.after(clone);
        clone.attr("class", "archive_clone").addClass('hide');

        var
          acv = wgt; //ウィジェット
          acvLi = acv.find("li"); //ウィジェット内のli全て
        //ul.yearsをアーカイブウィジェット直下に追加してそのDOMを取得
        var acv_years =  acv.append('<ul class="years"></ul>').find("ul.years");

        //liのテキストから年がどこからあるかを調べる
        acvLi.each(function(i) {
          var reg = /(\d+)年(\d+)月/;
          //日付表示+投稿数か
          if ( has_date_count ) {
            reg = /(\d+)年(\d+)月\s\((\d+)\)/;
          }
          var dt = $(this).text().match(reg);
          year.push(dt[1]);

        });
        $.unique(year); //重複削除

        acvLi.unwrap(); //liの親のulを解除

        //投稿年があるだけ中にブロックを作る
        var
          yearCount = year.length,
          i = 0;
        while (i < yearCount) {
          acv_years.append("<li class='year_" + year[i] + "'><a class='year'>" + year[i] + "年</a><ul class='month'></ul></li>");
          i++;
        }

        //作ったブロック内のulに内容を整形して移動
        //オリジナルのクローンは順番に削除
        var j = 0;
        acvLi.each(function(i, el) {
          var reg = /(\d+)年(\d+)月/;
          //日付表示+投稿数か
          if ( has_date_count ) {
            reg = /(\d+)年(\d+)月\s\((\d+)\)/;
          }
          var
            dt = $(this).text().match(reg),
            href = $(this).find("a").attr("href");

          //月の追加
          var rTxt = "<li><a href='" + href + "'>" + "" + dt[2] + "月</a>";
          //日付表示+投稿数か
          if ( has_date_count ) {
            rTxt += " (" + dt[3] + ")" + "</li>"; //投稿数の追加
          }

          //作成した月のHTMLを追加、不要なものは削除
          if (year[j] === dt[1]) {
            acv_years.find(".year_" + year[j] + " ul").append(rTxt);
            $(this).remove();
          } else {
            j++;
            acv_years.find(".year_" + year[j] + " ul").append(rTxt);
            $(this).remove();
          }
        });

        //クローン要素を削除
        clone.remove();

        //直近の年以外は非表示
        acv.find("ul.years ul:not(:first)").addClass("hide");

        //年をクリックで展開
        acv.find("a.year").on("click", function() {
          $(this).next().toggleClass("hide");
        });
      }//if has_date_count || has_date_only
    });//wgts.each

  });

})(jQuery);

直近の年以外は最初、非表示になっています。
クリックすると表示されますが、最初から全年表示したいという方は89〜90行目のコードを削除してください。

直近の2年分を表示したい場合は、89〜90行目のコードを以下のコードに書き換えてください。

        //直近2年(0番目と1番目のul.month)以外は非表示
        acv.find("ul.years > li:gt(1) ul.month").addClass("hide");

修正版

ここからはただの自己満のコードを載せておきます。

以下の点を修正しました。

  1. 月の表示を等間隔にして、1行に6ヶ月ずつ並べる(画面幅が狭いスマホでは3列表示にする)
  2. 月の表示の行間を狭める
  3. ウィンドウを縮小した際、2桁月の表示が改行されてしまうので折り返し禁止にする
  4. 月の並び順を降順(12月→1月)から、昇順(1月→12月)に変更

1〜3はCSS、4はJavaScriptの管轄です。

Geminiに上記のコードを投げたら、「無駄な処理」や「非効率なDOM操作」がいくつか見受けられるとのことで、ぱぱっと簡素化・最適化してくれました。

私には何が何だかさっぱり(笑)ですが、こういうプログラミング系にはめちゃくちゃ強いですねAIは。

最終的にこうなりました↓

修正版

/*--- 折り畳みアーカイブウィジェット ---*/
/* 各年の親要素:クリックできることを示し、区切り線を入れる */
.widget_archive a.year {
    cursor: pointer;
    border-bottom: 1px dotted #ccc; /* 各年に下線を引く */
    display: block; /* クリック領域を広げる */
}
/* 各年横のアイコン */
.widget_archive a.year::after {
    font-family: "Font Awesome 5 Free";
    content: '\f107'; /* 下向き矢印のアイコン */
    margin-left: 8px; /* アイコンの位置 */
    font-weight: bold;
}
/* 各月の横並び(フレックスボックス)の設定 */
.widget_archive .years ul {
    display: flex;
    flex-flow: row wrap; /* 折り返しを許可 */
    font-size: 1rem;
    line-height: 1.5; /* 行の高さを低くする */
    text-align: center; /* 中央寄せで等間隔感を出す */
    white-space: nowrap; /* 月名(12月など)が途中で改行されないように固定 */
    text-decoration: underline; /* 各月のリンクに下線を引く */
}
/* 1行に6ヶ月ずつ並べる(PCサイズ) */
.widget_archive ul.years li {
    flex: 0 0 calc(100% / 6); /* 6列 */
}
/* レスポンシブ対応:画面幅が狭いときは3列にする */
@media (max-width: 480px) {
  .widget_archive ul.years li {
    flex: 0 0 calc(100% / 3); /* 3列 */
  }
}
/* マウスホバー時のエフェクト */
#sidebar .widget_archive ul.years li :hover {
    background: none;
    transition: 0.1s;
    color: #72c7e6;
}
/* jQueryで .hide を toggle する場合、CSSは以下のようにシンプルでOK */
.widget_archive .hide {
  display: none;
}
/////////////////////////////////////
// 折り畳み式アーカイブウィジェット
/////////////////////////////////
(function($) {
  $(function() {
    $(".widget_archive").each(function() {
      var $wgt = $(this);
      var wgtText = $wgt.text();

      // 正規表現を一度だけ定義
      var regCount = /(\d+)年(\d+)月\s\((\d+)\)/;
      var regSimple = /(\d+)年(\d+)月/;
      
      var hasCount = wgtText.match(regCount);
      var hasDate = wgtText.match(regSimple);

      // ドロップダウン表示時はスキップ
      if (!hasDate) return;

      var $listItems = $wgt.find("li");
      var years = [];

      // 1. 年のリストを抽出
      $listItems.each(function() {
        var match = $(this).text().match(regSimple);
        if (match) years.push(match[1]);
      });
      years = $.unique(years);

      // 2. 新しい構造(ul.years)を作成
      var $acvYears = $('<ul class="years"></ul>');
      $.each(years, function(i, y) {
        $acvYears.append('<li class="year_' + y + '"><a class="year">' + y + '年</a><ul class="month"></ul></li>');
      });

      // 3. 既存のliを新しい構造に振り分け
      $listItems.each(function() {
        var $li = $(this);
        var match = $li.text().match(hasCount ? regCount : regSimple);
        if (!match) return;

        var y = match[1], m = match[2], count = match[3];
        var href = $li.find("a").attr("href");
        
        var linkText = m + "月" + (hasCount ? " (" + count + ")" : "");
        var $newLi = $("<li>").append($("<a>").attr("href", href).text(linkText));

        // 該当する年のulに追加(prependで昇順、appendで降順)
        $acvYears.find(".year_" + y + " .month").prepend($newLi);
      });

      // 4. DOMを入れ替え
      $wgt.find("ul").first().replaceWith($acvYears);

      // 5. インタラクション設定
      $acvYears.find("ul.month:not(:first)").hide(); // 最初以外非表示
      $acvYears.on("click", "a.year", function(e) {
        e.preventDefault();
        $(this).next(".month").slideToggle(200);
      });
    });
  });
})(jQuery);

ハイライトしてあるところが大きく変わった部分です。

まとめ

今回のカスタマイズでこだわったのは二点。

  • 各年の横に矢印アイコンを表示して開閉式であることを示した
  • 各月にアンダーラインを引き、リンクだと分かりやすくした

ユーザビリティ重視です。

コピペするだけで簡単に実装できるので、アーカイブが長くなって困っている方はぜひいかがでしょうか。

コメント

  1. ためになる情報に感謝です。各月の後に投稿数を表示させたいのですが、投稿数を表示するにチェックを入れても表示されません。

    アドバイス頂けると助かります。どうぞ、よろしくお願い致します。

    • I より:

      返事が遅くなり申し訳ありません。

      確かにチェックを入れても投稿数が表示されないですね…。
      色々と調べたりコードをいじったりしてみたのですが、私の力では解決することができず…。
      お役に立てなくてすみません…。

  2. hyouhyou より:

    参考にさせていただいて年別に表示できていたのですが急に元に戻ってしまいました。
    ワードプレスやcocoonのバージョンアップのせいかなと思いましたが自分には対処法がわかりませんでした。とても気に入っていたので何とか元に戻したいです。ご教示いただきますようお願いいたします。
    なお、現在はとりあえず開閉式で表示しています。

    • I より:

      返信が遅くなり申し訳ありません。

      私の方でもWordPressとCocoonをしばらくぶりに最新版にバージョンアップしてみましたが、問題なく動作しました。
      なのでそれ以外が原因だとは思うのですが…。
      月並みではありますが、ソースコードに間違いがないか、プラグインが干渉していないか等、今一度確認してみてください。

  3. kazu より:

    このカスタマイズ情報は、分かりやすく参考にさせていただいています。

    現在、直近の年以外は非表示になっています。
    「直近の2年以外は非表示」に変更する方法が分かりましたら教えていただけますか
    よろしくお願いいたします。

    • I より:

      自分では分からなかったのでGeminiに力を借りました笑

      当ページの目次4「jQueryのソースコード」内のハイライトしてある89〜90行目のコード↓
      //直近の年以外は非表示
      acv.find(“ul.years ul:not(:first)”).addClass(“hide”);

      これを下記のコードに置き換える↓
      // 直近2年(0番目と1番目のul.month)以外は非表示にする
      acv.find(“ul.years > li:gt(1) ul.month”).addClass(“hide”);

      私はこれで行けたのですが、いかがでしょうか?

      • kazu より:

        すべて貼り付けたら!マークがでて、うまくいきませんでした。
        少しずつ置き換えてできました。

        助かりました ありがとうございました