タグに基づいて関連記事を取得する Astro


各記事の下部に関連記事を紹介しています.

これらは最も近いタグに基づいています.この記事では、これを Astro で再現する方法を説明します.



関連記事の取得



最初に行うことは、単純なユース ケースを作成することです.最新の 2 つの記事を紹介します.

コンポーネント ディレクトリに RelatedArticles.astro という名前のコンポーネントを作成します.

フロントマター セクションでは、すべての投稿をロードすることから始めます.fetchContent は無限ループを引き起こすため、ここでは機能しないことに注意してください.

---
const fetchedPosts = await import.meta.glob("../pages/posts/*.md");
const allPosts = await Promise.all(
    Object.keys(fetchedPosts).map((key) => {
      const post = fetchedPosts[key];
      const url = key.replace("../pages/", "/").replace(".md", "/");
      return post().then((p) => {
        return { ...p.frontmatter, url };
      });
    });
);
---


次に、現在の記事を表示しないようにし、日付で並べ替えます.

// Retrieve the props from the component
const { tags, currentPathname } = Astro.props;

const mappedTags = allPosts
  .filter(({ url }) => url !== currentPathname)
  .filter((a) => new Date(a.date) <= new Date())
  .sort((a, b) => new Date(b.date) - new Date(a.date));


そして、HTML セクションでそれらのうちの 2 つを返すことができます.

<div class="container md:mx-auto">
  <div class="mx-0 md:-mx-4 grid grid-cols-1 md:grid-cols-2">
    <article article="{mappedTags[0]}" />
    <article article="{mappedTags[1]}" />
  </div>
</div>


注: 私が作成した既存の Article コンポーネントを使用しています.

関連記事を投稿テンプレートに追加できるようになりました.

<RelatedArticles tags={content.tags} currentPathname={canonicalURL.pathname} />


現在の投稿のタグと、ユーザーがいるページの現在のパス名を渡しています.

私のものをコピー 関連記事ランキング



スクリプトの準備ができたので、最後の 2 つの記事が表示されますが、主に相互に関連していない可能性があります.

私はいくつかのルールを考え出しました.これは次の順序にする必要があります.
  • すべてのタグが一致
  • 一部のタグは
  • に一致します
  • 1 つのタグが
  • に一致
  • 一致するタグがありません

  • これらはすべて日付に基づいているため、最新の記事と一致します.

    私のタグは、次のようなマークダウンのフロントマター セクションです.

    ---
    layout: ../../layouts/Post.astro
    ...
    tags:
      - developer
      - javascript
      - css
    ---
    


    もちろん、記事にこれらのタグがすべて含まれている場合、それは完全に一致しているため、最初にそれを表示する必要があります.

    この時点で、これを設定するのはかなり大変なことであることに気付きました.実際に動作する例もありましたが、少し厄介なように見えました.
    そこで、友人にアドバイスを求めることにしました.

    彼はクレイジーな解決策を思いついたのですが、それは完璧に機能することが判明しました!

    最初に、各記事のすべてのタグを照合します.
    フィルターと並べ替えの設定が既にあるので、それに削減を追加できます.

    const mappedTags = allPosts
      .filter(({ url }) => url !== currentPathname)
      .filter((a) => new Date(a.date) <= new Date())
      .sort((a, b) => new Date(b.date) - new Date(a.date))
      .reduce(
        (filtered, article) => {
          // TODO
        },
        { all: [], some: [], one: [], none: [] }
      );
    


    には、アキュムレータと現在の値があります.
    デフォルトとして、カウントしたいタイプのオブジェクトに値を設定します.

    最初にやりたいことは、削減された記事のタグがページのタグと一致する数を数えることです.

    実装したこの関数を介して posts タグにアクセスできることを思い出してください.

    const { tags, currentPathname } = Astro.props;
    



    const mappedTags = allPosts
      .filter(({ url }) => url !== currentPathname)
      .filter((a) => new Date(a.date) <= new Date())
      .sort((a, b) => new Date(b.date) - new Date(a.date))
      .reduce(
        (filtered, article) => {
          // nice use of type coercion: true => 1, false => 0, so we can add a boolean to number here
          const foundTagsCount = tags.reduce(
            (count, tag) => count + article.tags.includes(tag),
            0
          );
        },
        { all: [], some: [], one: [], none: [] }
      );
    


    正直に言うと、これは Alex のちょっとした魔法のようなものだとわかりました.別の reduce を使用していますが、ここでは一致するタグの数を合計しています.

    最終的に、reduce は元の記事に一致するタグの数です.

    次に、金額がどのカテゴリに適合するかを定義する必要があるため、これは次のいずれかになります.

    const amount =
      tags.length === foundTagsCount
        ? 'all'
        : foundTagsCount > 1
        ? 'some'
        : foundTagsCount
        ? 'one'
        : 'none';
    


    したがって、すべてのタグに一致する場合は、それを foundTagsCount にプッシュします.カウントがすべてではなく複数一致する場合は、それを all などにプッシュします.

    次に、それを主要な reduce 関数のアキュムレータ値にプッシュする必要があります.

    filtered[amount].push(article);
    return filtered;
    


    各カテゴリのすべての記事に一致するきちんとした配列が得られました.

    そして、それらを 1 つの大きな配列に広げて、表示したい最初の x の量を取ることができます.

    const { all, some, one, none } = mappedTags;
    const output = [...all, ...some, ...one, ...none];
    

    some 変数は、私の場合、最初の 2 つを使用するために拡散の順序になります.

    <div class="container md:mx-auto">
      <div class="mx-0 md:-mx-4 grid grid-cols-1 md:grid-cols-2">
        <article article="{output[0]}" />
        <article article="{output[1]}" />
      </div>
    </div>
    


    かなりの挑戦ですが、タグに基づいていくつかのクールな推奨事項を作成しました.
    将来、これにさらにいくつかのフィルタリング オプションを追加する可能性がありますが、現時点で必要なものに近いようです.

    1 読んでいただきありがとうございます。接続しましょう。



    私のブログを読んでいただきありがとうございます.メール ニュースレターを購読して、 に接続してください.