CMS モジュールの使用方法
注目すべき点
v3.2.3 - 3.2.4 の更新で、NEXTY.DEV の CMS は TipTap を使用してリファクタリングされ、より多くの機能を獲得し、コンテンツエディタの使用体験もより完璧になりました。
サポートされている機能
NEXTY.DEV ボイラープレートが提供する CMS 機能は、すべての SaaS ボイラープレートの中で最も包括的なものの一つで、非常に豊富な機能をサポートしています。TipTap の豊富なプラグインエコシステムを通じて、さらに多くの機能を簡単に拡張できます。
以下は、NEXTY.DEV ボイラープレートが既にサポートしている機能です:
コア機能
- 複数コンテンツモジュールサポート:デフォルトでブログ(blog)と用語集(glossary)の2つのモジュールを提供
- 統一されたアーキテクチャ設計:基本コンポーネントが共通で、データテーブルが共有されており、最小限のファイルとコードを追加するだけで新しいコンテンツモジュールを作成可能
- 複数コンテンツソースサポート:ローカル MDX ファイルのレンダリングとサーバーサイド CMS データのレンダリングをサポートし、各モジュールは独立して設定可能
- 閲覧統計:閲覧数の統計をサポートし、2つのモードを提供:
allモード:ページ読み込みのたびにカウントuniqueモード:同じ IP アドレスで1時間に1回のみカウント
- 目次ナビゲーション(TOC):詳細ページで記事の目次を自動生成し、デスクトップサイドバーとモバイル折りたたみ表示をサポート
- 関連記事の推薦:詳細ページで関連記事の表示をサポート(同じタグを判断基準として)
- カバー画像サポート:ローカルアップロード、外部リンク、CloudFlare R2 選択をサポート
- AI 翻訳:エディタに組み込まれた翻訳ボタンをサポートし、選択したコンテンツの迅速な翻訳を可能に
- 柔軟な設定:ツールバーのほとんどのプラグインは設定を通じて有効化または無効化可能
コンテンツ管理機能
コンテンツの作成・編集でサポートされる機能:
- 基本情報:
- タイトル(title)、URL エイリアス(slug)、説明(description)
- タグ(tags)管理、最大5つのタグをサポート
- カバー画像アップロード(ローカルアップロード、外部リンク、CloudFlare R2 選択をサポート)
- 多言語サポート:
- コンテンツ言語の選択(設定されたすべての言語をサポート)
- 異なる言語で同じ slug の設計をサポート
- 高度な機能:
- ステータス設定:下書き(draft)、公開(published)、アーカイブ(archived)
- 可視性制御:公開(public)、ログインユーザー(logged_in)、購読者(subscribers)
- ピン留め機能:重要なコンテンツをピン留めして表示することをサポート
- コンテンツ保護:ログインまたは購読が必要なコンテンツの場合、システムは自動的にアクセス制限のプロンプトを表示
ダッシュボード管理機能
- データテーブル表示:
- すべてのコンテンツのページネーション付き閲覧
- 検索フィルタリングをサポート(タイトル、slug、説明)
- ステータス、言語によるフィルタリングをサポート
- タグ管理:
- タグの作成、編集、削除
- タグはコンテンツモジュールに関連付け(各モジュールは独立したタグシステムを持つ)
- 一括操作:
- コンテンツの複製(duplicate)機能
- コンテンツの削除
- カバー画像管理:
- リストページでカバー画像を表示するかどうかの設定をサポート(
showCoverInList設定項目) - カバー画像がアップロードされていない場合、動的 OG 画像を自動生成
- リストページでカバー画像を表示するかどうかの設定をサポート(
ディレクトリ構造
components/cms/ // CMS 共通コンポーネント
├─ PostDataTable.tsx // ダッシュボードリスト & ページネーション
├─ PostEditorClient.tsx // 作成/編集エントリ(クライアントコンポーネント)
├─ PostForm.tsx // フォームコンポーネント
├─ PostList.tsx // フロントエンド無限スクロールリスト
├─ PostCard.tsx // フロントエンドコンテンツカード
├─ PostListActions.tsx // ダッシュボードアクションボタン(編集、複製、削除)
├─ RelatedPosts.tsx // 関連記事コンポーネント
├─ ContentRestrictionMessage.tsx // コンテンツアクセス制限プロンプト
├─ ImageUpload.tsx // 画像アップロードコンポーネント(R2 をサポート)
├─ TagInput.tsx // タグ入力コンポーネント
├─ TagSelector.tsx // タグセレクター(フロントエンドフィルタリング)
├─ TagSelectDialog.tsx // タグ選択ダイアログ
├─ TagCreateForm.tsx // タグ作成フォーム
├─ TagManagementDialog.tsx // タグ管理ダイアログ
└─ post-config.ts // PostType 設定センター
components/tiptap/ // TipTap リッチテキストエディタ
├─ TiptapEditor.tsx // リッチテキストエディタメインコンポーネント
├─ TiptapRenderer.tsx // フロントエンド読み取り専用レンダラー
├─ ImageGridExtension.ts // 画像グリッドカスタム Node
├─ ImageGridNodeView.tsx // 編集モード画像グリッドビュー
├─ ImageGridReadOnlyView.tsx // 読み取りモード画像グリッドビュー
├─ R2ResourceSelector.tsx // R2 メディアセレクター
├─ TableMenu.tsx // テーブルフローティングツールバー
├─ TableOfContents.tsx // 目次生成コンポーネント
└─ TranslationButton.tsx // AI 翻訳ボタン
lib/cms/
└─ index.ts // CMS モジュールファクトリー関数
actions/posts/ // Server Actions
├─ posts.ts // コンテンツ CRUD + フロントエンド読み取り
├─ tags.ts // タグ CRUD
└─ views.ts // 閲覧数統計
app/[locale]/(protected)/dashboard/(admin)/blogs/
├─ page.tsx // ダッシュボードリストページ
├─ Columns.tsx // テーブル列定義
├─ new/page.tsx // 作成ページ
└─ [postId]/edit/page.tsx // 編集ページ
app/[locale]/(protected)/dashboard/(admin)/glossary/
├─ page.tsx // ダッシュボードリストページ
├─ Columns.tsx // テーブル列定義
├─ new/page.tsx // 作成ページ
└─ [postId]/edit/page.tsx // 編集ページ
app/[locale]/(basic-layout)/blog/
├─ page.tsx // フロントエンドリスト
└─ [slug]/
├─ page.tsx // 詳細ページ
└─ opengraph-image.tsx // 動的 OG 画像
app/[locale]/(basic-layout)/glossary/
├─ page.tsx // フロントエンドリスト
└─ [slug]/
├─ page.tsx // 詳細ページ
└─ opengraph-image.tsx // 動的 OG 画像
lib/db/schema.ts // Drizzle データモデル
// 関連テーブル:posts、tags、postTags
types/cms.ts // TypeScript 型定義
config/common.ts // 共通設定(画像パスなど)
設定説明
PostConfig 設定項目
components/cms/post-config.ts で、各コンテンツモジュールには以下の設定項目があります:
export interface PostConfig {
postType: PostType; // コンテンツタイプ
schema: z.ZodSchema; // 検証スキーマ
actionSchema: z.ZodSchema; // アクション検証スキーマ
imagePath: string; // 画像保存パス
enableTags: boolean; // タグを有効にするかどうか
localDirectory?: string; // ローカル MDX ファイルディレクトリ(オプション)
viewCount: ViewCountConfig; // 閲覧数統計設定
showCoverInList: boolean; // リストページでカバー画像を表示するかどうか
routes: { // ルート設定
list: string;
create: string;
edit: (id: string) => string;
};
}閲覧数統計設定
export interface ViewCountConfig {
enabled: boolean; // 閲覧数統計を有効にするかどうか
mode: 'all' | 'unique'; // 統計モード
showInUI: boolean; // UI に表示するかどうか
}機能展示
CMS 機能はすべて WYSIWYG であるため、ここでは詳しく説明しません。画像を通じて機能を理解できます。






画像アップロードはローカルアップロード、外部リンク、CloudFlare R2 選択をサポート


画像表示は複数の画像を並べて表示することをサポート

YouTube 動画の挿入をサポート

エディタコンテンツはクイック翻訳をサポート

コンテンツエディタ機能の変更方法
コンテンツエディタのすべての機能ファイルは components/tiptap の下にあります。コードに慣れた後で変更することも、AI に変更を依頼することもできます。AI は Tiptap に非常に精通しています。
エディタ設定オプション
TiptapEditor コンポーネントは以下の設定をサポートします:
interface TiptapEditorProps {
content: string;
onChange: (content: string) => void;
placeholder?: string;
disabled?: boolean;
enableYoutube?: boolean; // YouTube 動画を有効にする
enableImage?: boolean; // 画像アップロードを有効にする
enableCodeBlock?: boolean; // コードブロックを有効にする
enableTable?: boolean; // テーブルを有効にする
enableBlockquote?: boolean; // ブロッククォートを有効にする
enableHorizontalRule?: boolean; // 水平線を有効にする
enableR2Selector?: boolean; // R2 リソースセレクターを有効にする
r2PublicUrl?: string; // R2 パブリックアクセス URL
imageUploadConfig?: {
maxSize?: number; // ファイルサイズ制限(バイト)
filenamePrefix?: string; // ファイル名プレフィックス
path?: string; // アップロードパス
};
enableTranslation?: boolean; // AI 翻訳を有効にする
postType?: PostType; // コンテンツタイプ
outputFormat?: "markdown" | "text" | "html"; // 出力形式
}新しいコンテンツモジュールの追加方法
コンテンツサイトを開発している場合、ブログと用語集モジュールでは不十分な場合があります。複数のコンテンツモジュールを追加して、サイトのコンテンツ構造を豊かにしたい場合、NEXTY.DEV ボイラープレートを使用すれば簡単に解決できます。
新しい guide(ガイド)モジュールを追加する例として、以下の手順を完了するだけで済みます:
1. データベーススキーマの拡張
lib/db/schema.ts で CMS コンテンツタイプを拡張:
export const postTypeEnum = pgEnum('post_type', [
'blog',
'glossary',
'guide', // 新規追加
])次に、データベースマイグレーションコマンドを実行:
pnpm db:generate
pnpm db:migrate2. CMS 設定の拡張
components/cms/post-config.ts で新しいモジュール設定を追加:
export const POST_CONFIGS: Record<PostType, PostConfig> = {
blog: {
// ... 既存の設定
},
glossary: {
// ... 既存の設定
},
// 新しい guide 設定
guide: {
postType: "guide",
schema: basePostSchema,
actionSchema: postActionSchema,
imagePath: GUIDE_IMAGE_PATH, // config/common.ts で定義する必要がある
enableTags: true,
// localDirectory: 'guides', // ローカル MDX ファイルをサポートする必要がある場合
viewCount: {
enabled: true, // 閲覧数統計を有効にする
mode: 'unique', // ユニーク IP 統計を使用
showInUI: true,
},
showCoverInList: true,
routes: {
list: "/dashboard/guides",
create: "/dashboard/guides/new",
edit: (id: string) => `/dashboard/guides/${id}`,
},
},
};3. 画像パス設定の追加
config/common.ts で追加:
export const GUIDE_IMAGE_PATH = "guide-images";
export const R2_CATEGORIES: R2Category[] = [
{ name: "All", prefix: "" },
{ name: "Admin Uploads", prefix: `${ADMIN_UPLOAD_IMAGE_PATH}/` },
{ name: "Blogs Images", prefix: `${BLOGS_IMAGE_PATH}/` },
{ name: "Glossary Images", prefix: `${GLOSSARY_IMAGE_PATH}/` },
{ name: "Guide Images", prefix: `${GUIDE_IMAGE_PATH}/` }, // 新規追加
];4. ダッシュボード管理ページの作成
app/[locale]/(protected)/dashboard/(admin)/glossary フォルダをコピーし、guides にリネーム。
以下のファイルを変更:
guides/page.tsx:
// postType を "guide" に変更
const result = await listPostsAction({
pageIndex: 0,
pageSize: PAGE_SIZE,
postType: "guide", // ここを変更
});
// 設定を更新
<PostDataTable
config={{
postType: "guide", // ここを変更
columns,
listAction: listPostsAction,
createUrl: "/dashboard/guides/new", // ここを変更
enableTags: true,
searchPlaceholder: "Search guides...", // ここを変更
}}
// ...
/>guides/Columns.tsx:必要に応じてテーブル列定義を調整。
guides/new/page.tsx と guides/[postId]/edit/page.tsx:
<PostEditorClient
postType="guide" // ここを変更
mode="create" // または "edit"
r2PublicUrl={r2PublicUrl}
postId={postId}
/>5. フロントエンド表示ページの作成
app/[locale]/(basic-layout)/glossary フォルダをコピーし、guide にリネーム。
guide/page.tsx:
// CMS モジュールインスタンスを作成(lib/cms/index.ts で)
export const guideCms = createCmsModule('guide');
// ページで使用
const { posts: localPosts } = await guideCms.getLocalList(locale);
const initialServerPostsResult = await listPublishedPostsAction({
pageIndex: 0,
pageSize: SERVER_POST_PAGE_SIZE,
postType: "guide", // ここを変更
locale: locale,
});
// タグ
const tagsResult = await listTagsAction({ postType: "guide" });
// PostList コンポーネント
<PostList
postType="guide"
baseUrl="/guide"
localPosts={localPosts}
initialPosts={initialServerPosts}
initialTotal={totalServerPosts}
serverTags={serverTags}
locale={locale}
pageSize={SERVER_POST_PAGE_SIZE}
showTagSelector={true}
showCover={POST_CONFIGS.guide.showCoverInList}
emptyMessage="No guides found for this tag."
/>guide/[slug]/page.tsx:
// guideCms を使用してコンテンツを取得
const { post, errorCode } = await guideCms.getBySlug(slug, locale);
// 閲覧数統計
const viewCountConfig = POST_CONFIGS.guide.viewCount;
if (viewCountConfig.enabled) {
if (viewCountConfig.mode === "unique") {
await incrementUniqueViewCountAction({ slug, postType: "guide", locale });
} else {
await incrementViewCountAction({ slug, postType: "guide", locale });
}
}
// 関連記事
<RelatedPosts
postId={post.id}
postType="guide"
limit={10}
title="Related Guides"
locale={locale}
CardComponent={GuidePostCard}
/>6. lib/cms/index.ts で新しいモジュールをエクスポート
// ファイルの末尾に追加
export const guideCms = createCmsModule('guide');7. sitemap.ts の更新
app/sitemap.ts で Guide ページのルートを追加:
// guide リストページを追加
{
url: `${siteUrl}/${locale}/guide`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.8,
}
// guide 詳細ページを追加
const guideResult = await listPublishedPostsAction({
locale: locale,
pageSize: 1000,
visibility: "public",
postType: "guide",
});
if (guideResult.success && guideResult.data?.posts) {
guideResult.data.posts.forEach((post) => {
sitemap.push({
url: `${siteUrl}/${locale}/guide/${post.slug}`,
lastModified: post.updatedAt ? new Date(post.updatedAt) : new Date(),
changeFrequency: 'weekly',
priority: 0.7,
});
});
}8. 国際化翻訳の追加
messages/ ディレクトリの各言語ファイルに関連する翻訳を追加。
注意事項
-
ローカル MDX ファイルサポート:新しい CMS モジュールがローカル MDX ファイルをサポートする必要がない場合、
localDirectory設定項目を設定せず、データベースを直接使用してください。 -
独立したタグシステム:各コンテンツモジュールのタグシステムは独立しており、
postTypeフィールドで区別されます。 -
画像パス計画:各コンテンツモジュールに独立した画像保存パスを設定し、管理と整理を容易にします。
-
閲覧数統計:閲覧数統計機能を使用するには Redis の設定が必要です。Redis が設定されていない場合、システムは適切に降格し、0 カウントを返します。
-
コンテンツの可視性:
public:すべての人に表示logged_in:ログインが必要subscribers:購読が必要(actions/posts/posts.tsのcheckUserSubscription関数で購読ロジックをカスタマイズ)
- SEO 最適化:
- カバー画像がアップロードされていない場合、システムは自動的に動的 OG 画像を生成
- 新しいモジュールのルートを含めるように
sitemap.tsを更新することを忘れないでください constructMetadata関数を使用して正しいメタデータを確保
これで、まったく新しい CMS モジュールが完成しました!
自分でモジュールを追加するのが面倒だと感じる場合は、ドキュメントリンクを AI に送信してください。AI がすべての手順を完了するのを手伝います。
まとめ
NEXTY.DEV の CMS システムには以下の利点があります:
- 明確なアーキテクチャ:統一された設定センターで、拡張と保守が容易
- 包括的な機能:コンテンツの作成、編集からフロントエンド表示まで、すべてが揃っています
- 柔軟な設定:各モジュールは独立して機能特性を設定可能
- 優れたユーザー体験:TipTap エディタは強力で、操作がスムーズ
- 高い開発効率:新しいモジュールの追加には最小限のコードのみが必要で、ほとんどのコンポーネントは再利用可能
- 型安全性:完全な TypeScript 型定義
- パフォーマンス最適化:無限スクロール、ページネーション、キャッシュなどの最適化手段をサポート
個人ブログ、企業コンテンツサイト、複雑なマルチモジュールコンテンツプラットフォームのいずれであっても、NEXTY.DEV の CMS システムが簡単に対応できます!