WordPress ナビゲーションメニューに最近の投稿を追加

WordPress のナビゲーションメニューに、動的に最近の投稿のメニュー項目を追加する方法を紹介します。

当初は、管理画面から細かく設定できるようにしてプラグインにしようと思っていたのですが、ナビゲーションメニューの設定画面を設けるのが意外と面倒だったので、プラグイン化は先送りにして設定画面なしのシンプルなものを先行して紹介することにした次第です。

仕様

  • 管理画面のメニュー設定に [最近の投稿] メニュー項目を追加する。
  • 最近の投稿メニューは表示時にサブメニューを追加しサブメニューには最近の投稿へのメニューを10件表示する。
  • 投稿日が30日以内の場合は「NEW!」マークを表示する。

スクリーンショット

メニュー設定

Twenty Seventeen テーマの表示例

Twenty Sixteen テーマの表示例

コード

functions.php に下記コードを追加します。

class Recent_Posts_Nav_Menu {
	function __construct() {
		add_action( 'admin_head-nav-menus.php', array( $this, 'add_meta_box' ) );
		add_filter( 'wp_setup_nav_menu_item', array( $this, 'setup_nav_menu_item' ) );
		add_filter( 'wp_get_nav_menu_items', array( $this, 'get_nav_menu_items' ) );
	}

	function add_meta_box() {
		add_meta_box( 'add-recent-posts', '最近の投稿', array( $this, 'meta_box_content' ), 'nav-menus', 'side', 'default' );
	}

	function setup_nav_menu_item( $menu_item ) {
		if ( isset( $menu_item) ) {
			if ($menu_item->object == 'recent_posts') {
		        $menu_item->type_label = '最近の投稿';
		    }
		}
		return $menu_item;
	}

	function meta_box_content() {
		global $nav_menu_selected_id;

		$items = array();
		$item = new stdClass();
		$item->classes = array();
		$item->type = 'recent_post';
		$item->object_id = 1;
		$item->object = 'recent_posts';
		$item->title = '最近の投稿';
		$item->menu_item_parent = null;
		$item->url = null;
		$item->target = null;
		$item->attr_title = null;
		$item->xfn = null;
		$item->db_id = 0;
		$item->description = null;
		$items[] = $item;

		$walker = new Walker_Nav_Menu_Checklist( array() );

		echo '<div id="recent-posts" class="posttypediv">';
		echo '<div id="tabs-panel-recent-posts" class="tabs-panel tabs-panel-active">';
		echo '<ul id="recent-posts-checklist" class="categorychecklist form-no-clear">';
		echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $items ), 0, (object)array( 'walker' => $walker ) );
		echo '</ul>';
		echo '</div>';
		echo '</div>';
		echo '<p class="button-controls">';
		echo '<span class="add-to-menu">';
		echo '<input type="submit"' . wp_nav_menu_disabled_check( $nav_menu_selected_id ) . ' class="button-secondary submit-add-to-menu" value="' . esc_attr__( 'Add to Menu' ) . '" name="add-recent-posts-menu-item" id="submit-recent-posts" />';
		echo '</span>';
		echo '</p>';
	}

	function get_nav_menu_items( $items ) {
	    if ( is_admin() ) {
			return $items;
		}

		$new_days = 30;	// 最新の日数

		$menu_order = count( $items );
		$add_item_count = 0;
		$today = date( 'U' );
		foreach ( $items as $item ) {
			if ( $item->post_type == 'nav_menu_item' && $item->object == 'recent_posts' ) {
				$child_items = array();
				$posts = get_posts( array(
					'post_type' => 'post',
					'posts_per_page' => 10,
					'orderby' => 'date',
					'order' => 'DESC',
				) );
				foreach( $posts as $post ) {
					++$add_item_count;

					$days = date( 'U', ( $today - date( 'U', strtotime( $post->post_date ) ) ) ) / 86400;

					$child_item = new stdClass();
					$child_item->ID = 1000000 + $add_item_count;
					$child_item->type = $item->type;
					$child_item->object_id = $post->id;
					$child_item->object = 'recent-posts-child';
					$child_item->title = $post->post_title;
					$child_item->menu_item_parent = $item->ID;
					$child_item->url = get_permalink( $post->ID );
					$child_item->target = null;
					$child_item->attr_title = null;
					$child_item->xfn = null;
					$child_item->db_id = 0;
					$child_item->description = null;
					$child_item->post_type = 'nav_menu_item';

					$child_item->current = false;
					$child_item->classes = array();

					$child_item->menu_order = $menu_order + $add_item_count;
					if ( is_singular() && get_the_ID() == $post->ID ) {
						$child_item->classes[] = 'current-menu-item';
						$child_item->current = true;
					}
					if ( $new_days > $days ) {
						$child_item->classes[] = 'menu-item-new';
					}

					$child_items[] = $child_item;
				}
				$items = array_merge( $items, $child_items );
			}
		}
		return $items;
	}
}

new Recent_Posts_Nav_Menu();

スタイル (CSS)

style.css 等に下記スタイルを追加します。

/*
最近の投稿メニュー
*/
.main-navigation li.menu-item-new a:after {
	content: "NEW!";
	margin-left: 0.5rem;
	padding: 1px 2px;
	vertical-align: middle;
	font-size: .6rem;
	color: #fff;
	font-weight: bold;
	border-radius: 3px;
	background-color: #f02020;
}
.main-navigation ul ul li {
	min-width: 250px;
	white-space: nowrap;
	width: 100%;
}
.main-navigation ul ul a {
	width: auto;
	white-space: nowrap;
}

変更履歴

2020年8月6日
メニュー項目の current-menu-item クラスがアーカイブページの場合にも追加されてしまう不具合を修正しました。

コメント

  • WordPress 5.4.2 でテーマは Fukasawa なんですが「NEW!」マークが表示されません。テーマに依るんでしょうか?

    • こんにちは、コメントありがとうございます。
      Fukasawa テーマのメインメニューでしょうか?メインメニューの場合は、クラス名が main-navigation ではなく main-menu です。よって、サンプルの CSS で使用している .main-navigation をすべて .main-menu に置き換えないと表示されません。モバイルメニューの場合は、.mobile-menu に置き換えてください。

      Fukasawa テーマのメインメニューおよびモバイルメニューの両方を対象にする場合の例:

      .mobile-menu li.menu-item-new a:after,
      .main-menu li.menu-item-new a:after {
      content: "NEW!";
      margin-left: 0.5rem;
      padding: 1px 2px;
      vertical-align: middle;
      font-size: .6rem;
      color: #fff;
      font-weight: bold;
      border-radius: 3px;
      background-color: #f02020;
      }
      .mobile-menu ul ul li,
      .main-menu ul ul li {
      min-width: 250px;
      white-space: nowrap;
      width: 100%;
      }
      .mobile-menu ul ul a,
      .main-menu ul ul a {
      width: auto;
      white-space: nowrap;
      }

  • 有難うございます。返事が遅くなってすいません。教えて頂いた記述でstyle.cssを書き換えたんですが、どうも変化ありません・・・・function.phpの方も変えないといけないんでしょうか、それともfukasawaの特性でしょうか

    • Fukasawa テーマで試してみました。結果、下記のように表示されました。
      ブラウザのキャッシュではないでしょうか。キャッシュを削除してみてください。

      スクリーンショット

      functions.php の方はそのままです。今回の件とは、関係ありませんが、ちょっと不具合を修正したので更新してもらえたらと思います。

  • Macのsafari キャッシュ削除しても変わらずでchromeを新規インストールして見ても同じです。ちゃんと最新投稿10個は表示されて投稿に飛んでくれるんですが、NEWマークだけが・・・・スマホ(androidとiPhone両方でも)同じです。

  • そういえば、ダッシュボードの「サイトをカスタマイズ」に入ると以下のような文章が表示されます・・・・
    Fatal error: Uncaught Exception: Supplied nav_menu_item value missing property: status in /home/mszarame/www/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php:183 Stack trace: #0 /home/mszarame/www/wp-includes/class-wp-customize-nav-menus.php(753): WP_Customize_Nav_Menu_Item_Setting->__construct(Object(WP_Customize_Manager), ‘nav_menu_item[1…’, Array) #1 /home/mszarame/www/wp-includes/class-wp-hook.php(287): WP_Customize_Nav_Menus->customize_register(Object(WP_Customize_Manager)) #2 /home/mszarame/www/wp-includes/class-wp-hook.php(311): WP_Hook->apply_filters(NULL, Array) #3 /home/mszarame/www/wp-includes/plugin.php(478): WP_Hook->do_action(Array) #4 /home/mszarame/www/wp-includes/class-wp-customize-manager.php(928): do_action(‘customize_regis…’, Object(WP_Customize_Manager)) #5 /home/mszarame/www/wp-includes/class-wp-hook.php(287): WP_Customize_Manager->wp_loaded(”) #6 /home/mszarame/www/wp-includes/class-wp-hook.php(311): WP_Hook->apply_filters(NULL, Array) #7 /home/mszarame/www/wp-includes/plugin. in /home/mszarame/www/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php on line 183

  • 追加 CSSに記述したらNEWマークが!!! 成功しました!!! style.cssではだめなんですね、勉強になりました。fukasawaはスマホだとウイジェットが表示されないので最新投稿一覧がこういうふうにメニューに表示されるのは素晴らしいです!!!貴重な時間を割いていただいて大変有り難うございました、感謝・感激です
    石鷹

    • 出来たようで良かったです (^^♪
      style.css ではだめという訳ではないです。通常のテーマ (Fukasawa テーマも) は style.css を読み込むので反映されるはずなのですが、記述にミスがあったか記述する場所に問題があったか・・・ちょっと分かりません。とりあえず、カスタマイズの CSS で反映したということなので style.css よりもよい (テーマを更新しても消えないので) かもしれませんね。
      また何かありましたら気軽にコメントしてください。
      ではでは

  • 本当にありがとうございました。個人用と所属する写真クラブ用に2つのwordpress ブログに導入しました。好評です!!!!!!

佐藤稔 へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。

日本語でコメントを入力してください。(スパム対策)