Site cover image

Site icon imageトレモロの技術ブログ(組込み、Web系)

ポートフォリオなどを公開しています。

Post title iconSlugを自動生成【astro-notion-blogカスタマイズ】

概要

astro-notion-blogのカスタマイズ解説記事です。

スラッグは、適切な英単語2~3語がSEO的に良いとされています。が、私は設定するのがメンドクサイと感じました。

そこで、自動で文字列が入力されるようにカスタムしました。

notionデータベースのSlug列を関数に変更し、astro-notion-blog側を一部変更します。

手順

notionデータベース側

Slug列を関数プロパティに変更します。

Image in a image block

どのプロパティを選ぶかは自由ですが、一意の文字列にしなければURLが重複してしまいます。

私はid()を使用することにしました。

Image in a image block

💡
上記の変更だけを実施すると、astro-notion-blogから記事が読み込めなくなります。

以下に記載した変更も合わせて実施してください。


astro-notion-blog側

次に、astro-notion-blog側をSlug列を関数に変更した件に対応します。

具体的には、Slugの情報読み出し処理を関数プロパティに対応させます。

以下4ヶ所を変更することで記事が読み込めました。

①scripts/blog-contents-cache.cjs : getAllPages()

変更前

  const pages = results.map((result) => {
    return {
      id: result.id,
      last_edited_time: result.last_edited_time,
      slug: result.properties.Slug.rich_text
        ? result.properties.Slug.rich_text[0].plain_text
        : '',
    };
  });

変更後

  const pages = results.map((result) => {
    return {
      id: result.id,
      last_edited_time: result.last_edited_time,
      slug: result.properties.Slug.formula.string
        ? result.properties.Slug.formula.string
        : '',
    };
  });
②src/lib/notion/client.ts : _validPageObject()

変更前

function _validPageObject(pageObject: responses.PageObject): boolean {
  const prop = pageObject.properties
  
  
  return (
    !!prop.Page.title &&
    prop.Page.title.length > 0 &&
    !!prop.Slug.rich_text &&
    prop.Slug.rich_text.length > 0 &&
    !!prop.Date.date
  )
}

変更後

function _validPageObject(pageObject: responses.PageObject): boolean {
  const prop = pageObject.properties
  const slug_id = String(prop.Slug.formula.string)

  return (
    !!prop.Page.title &&
    prop.Page.title.length > 0 &&
    !!slug_id &&
    !!prop.Date.date
  )
}
③src/lib/notion/client.ts : _buildPost()

変更前

  const post: Post = {
    PageId: pageObject.id,
    Title: prop.Page.title
      ? prop.Page.title.map((richText) => richText.plain_text).join('')
      : '',
    Icon: icon,
    Cover: cover,
    Slug: prop.Slug.rich_text
      ? prop.Slug.rich_text.map((richText) => richText.plain_text).join('')
      : '',
    Date: prop.Date.date ? prop.Date.date.start : '',
    Tags: prop.Tags.multi_select ? prop.Tags.multi_select : [],
    Excerpt:
      prop.Excerpt.rich_text && prop.Excerpt.rich_text.length > 0
        ? prop.Excerpt.rich_text.map((richText) => richText.plain_text).join('')
        : '',
    FeaturedImage: featuredImage,
    Rank: prop.Rank.number ? prop.Rank.number : 0,
  }

変更後

  const post: Post = {
    PageId: pageObject.id,
    Title: prop.Page.title
      ? prop.Page.title.map((richText) => richText.plain_text).join('')
      : '',
    Icon: icon,
    Cover: cover,
    Slug: prop.Slug.formula.string
      ? String(prop.Slug.formula.string)
      : '',
    Date: prop.Date.date ? prop.Date.date.start : '',
    Tags: prop.Tags.multi_select ? prop.Tags.multi_select : [],
    Excerpt:
      prop.Excerpt.rich_text && prop.Excerpt.rich_text.length > 0
        ? prop.Excerpt.rich_text.map((richText) => richText.plain_text).join('')
        : '',
    FeaturedImage: featuredImage,
    Rank: prop.Rank.number ? prop.Rank.number : 0,
  }
④src/lib/notion/responses.ts : PageProperty

変更前

interface PageProperty {
  id: string
  type: string

  
  title?: RichTextObject[]
  rich_text?: RichTextObject[]
  number?: number
  select?: SelectProperty
  status?: StatusProperty
  multi_select?: SelectProperty[]
  date?: DateProperty
  formula?: FormulaProperty
  relation?: RelationProperty[]
  rollup?: RollupProperty
  people?: UserObject[]
  files?: FileObject[]
  checkbox?: boolean
  url?: string
  email?: string
  phone_number?: string
  created_time?: string
  created_by?: UserObject
  last_edited_time?: string
  last_edited_by?: UserObject
}

変更後

interface PageProperty {
  id: string
  type: string
  formula: FormulaProperty

  title?: RichTextObject[]
  rich_text?: RichTextObject[]
  number?: number
  select?: SelectProperty
  status?: StatusProperty
  multi_select?: SelectProperty[]
  date?: DateProperty
                          
  relation?: RelationProperty[]
  rollup?: RollupProperty
  people?: UserObject[]
  files?: FileObject[]
  checkbox?: boolean
  url?: string
  email?: string
  phone_number?: string
  created_time?: string
  created_by?: UserObject
  last_edited_time?: string
  last_edited_by?: UserObject
}

注意点

  • (当然ながら)手動でSlugを設定できなくなります。
  • すでに記事を公開済みの場合、URLが変更されます。リダイレクト等が必要かもしれません。
  • SEO的にマイナスになるかもしれませんので、ご了承を。

感想

Slugをいちいち考えて入力する、ひと手間が省けました。

これ以外にも執筆に集中できるカスタマイズを追加して、記事を量産できるようになりたいですね。

参考