ナビゲーションメニュー
このページで分かること
- 管理画面でのメニューの作成、リンクの追加(コンテンツ、カスタムリンク)、並べ替えと入れ子
- メニュー項目の種類ごとに、テンプレートに返されるURLがどう決まるか
getMenu()によるレイアウトでの描画、ロケールの選ばれ方、ウィジェットエリアでの使い方
このページの目次
メニューを使うと、編集者はサイトのテンプレートを変更せずに、順番の決まったリンクを管理できます。メニューは primary や footer のような変更しない前提の名前を持ち、翻訳したメニューごとに別々の項目を持ちます。
メニューの作成
メニューは、EmDashの管理画面の「メニュー」で作成し、並べ替えます。
-
「メニューを作成」をクリックし、名前とラベルを入力します。テンプレートは名前でクエリし、ラベルは管理画面でメニューを見分けるために使います。
-
エントリーへのリンクを追加するには「コンテンツを選択」を、外部URLまたはルートからの相対パスを入力するには「カスタムリンクを追加」をクリックします。
-
「上に移動」と「下に移動」で順番を設定します。項目を入れ子にするには、項目を編集して「親」を選びます。
すべてのロケールで同じメニュー名を使います。多言語サイトでは、メニューを開き、「翻訳」パネルから別のロケールの版を作成・編集します。EmDashは同じコンテンツやタクソノミーのタームの翻訳どうしをつないでおくため、getMenu() は要求されたロケールのラベルとスラッグを使えます。
やさしい解説
WordPressの「外観」→「メニュー」にあたる機能です。管理画面の「メニュー」でリンクを並べておけば、テンプレートのコードを変えずにナビゲーションを更新できます。メニューには、テンプレートから呼び出すための「名前」(例:primary)と、管理画面で見分けるための「ラベル」の2つがあります。テンプレートが参照するのは名前のほうです。
メニューのリンクが決まる仕組み
コンテンツとタクソノミーのメニュー項目は、完成したURLではなく参照を保存します。テンプレートが getMenu() を呼び出すと、EmDashはその時点のコレクションとロケールのデータを使って、参照からURLを決めます。
| メニュー項目の種類 | テンプレートに返されるURL |
|---|---|
| コンテンツのエントリー | コレクションの urlPattern。コレクションにパターンがない場合は /{collection}/{slug} |
| タクソノミーのターム | 解決したタームの翻訳を使った /{taxonomy}/{slug} |
| コレクションのアーカイブ | /{collection}/ |
| カスタムリンク | 編集者が入力した外部URLまたはルートからの相対パス |
返される各項目には、ラベル、任意のターゲット、title属性、CSSクラス、入れ子の children も含まれます。次の描画の例では、これらの値をそのまま使います。
やさしい解説
メニューにコンテンツやタームを追加しても、URLそのものは保存されません。保存されるのは「どのエントリーか」「どのタームか」という参照で、ページを表示するたびにURLが組み立てられます。そのため、あとから記事のスラッグやコレクションの urlPattern を変えても、メニューのリンクは新しいURLになります。カスタムリンクだけは、入力したURLがそのまま使われます。
メニューの描画
getMenu() は、サーバーで描画するAstroコンポーネントで呼び出します。その名前のメニューが存在しない場合は null を返します。
次のレイアウトは、primaryメニューと、1階層分の入れ子の項目を描画します。
---
import { getMenu } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";
const locale = Astro.currentLocale;
const menu = await getMenu("primary", { locale });
function menuHref(url: string) {
return locale && url.startsWith("/")
? getRelativeLocaleUrl(locale, url)
: url;
}
---
{menu && menu.items.length > 0 && (
<nav aria-label="Primary navigation">
<ul>
{menu.items.map((item) => {
const href = menuHref(item.url);
return (
<li class:list={item.cssClasses}>
<a
href={href}
target={item.target}
rel={item.target === "_blank" ? "noopener noreferrer" : undefined}
title={item.titleAttr}
aria-current={Astro.url.pathname === href ? "page" : undefined}
>
{item.label}
</a>
{item.children.length > 0 && (
<ul>
{item.children.map((child) => {
const childHref = menuHref(child.url);
return (
<li class:list={child.cssClasses}>
<a
href={childHref}
target={child.target}
rel={child.target === "_blank" ? "noopener noreferrer" : undefined}
title={child.titleAttr}
aria-current={Astro.url.pathname === childHref ? "page" : undefined}
>
{child.label}
</a>
</li>
);
})}
</ul>
)}
</li>
);
})}
</ul>
</nav>
)}
getMenu() は、明示的に指定した locale を最初に選び、次に現在のリクエストのロケール、次に設定された既定のロケールを選びます。そのロケールにメニューや参照先のエントリーがない場合は、設定されたフォールバックの順番に従って検索します。
メニュー項目のURLには、コレクションのURLパターンやタクソノミーのパスは含まれますが、Astroのロケールの接頭辞は含まれません。menuHref() ヘルパーは、ルートからの相対リンクにこの接頭辞を付け、外部リンクはそのままにします。
この例は子を1階層分だけ描画します。一般的なドロップダウンにはこれで足ります。編集者がもっと深いナビゲーションを作れる場合は、項目のマークアップを再帰的なコンポーネントに移し、各項目の children を同じルールで描画します。
ウィジェットエリアでのメニューの使用
メニューウィジェットは、既存のメニューをウィジェットエリアの中に配置します。このウィジェットは、現在のリクエストのロケールのメニューを読み込みます。独自の入れ子のマークアップや、ロケールのURLの明示的な処理が必要な場合は、上の直接描画する方法を使います。
メニューのデータの直接取得
1つのメニューの項目ではなく、利用できるメニューの定義が必要なテンプレートでは、getMenus() を使います。クエリの引数と戻り値はランタイムAPIリファレンスで説明しています。
プログラムからメニューを変更する場合は、Bearerトークンで認証し、状態を変更するすべてのリクエストに X-EmDash-Request: 1 を付けます。リクエストの本文とレスポンスはメニューのエンドポイントを参照してください。
ロケールのルーティングとフォールバックの設定は多言語対応を参照してください。