📝

LaravelとmicroCMSを連携してブログ記事を作成

に公開

都内で活動しているwebエンジニアです

プロジェクトでLaravelとmicroCMSを連携してブログを実装する事案がありました
今回はmicroCMSを使って「ブログ」「カテゴリ」の設定方法を記事に残したいと思います

Laravel側の環境は以下の通りです。

  • PHP 8.2
  • Laravel 11.0
  • microcmsio/microcms-php-sdk": "^1.0"
  • macOS 15.4.1
  • bootstrap@5.0.2

microCMS


https://microcms.io/

microCMSとは?

microCMSとは、日本発のAPIベースのヘッドレスCMSです。
「ヘッドレス」とは「見た目(フロントエンド)」を無くし、「コンテンツ管理(バックエンド)」をメインとした設計です。
従来のCMS(WordPress等)では、コンテンツの管理と表示が一体化していましたが、ヘッドレスCMSはコンテンツ管理に特化し、APIを通じてデータを提供します。これにより、フロントエンドの自由度が高まりWordpressよりも簡単にコンテンツ管理ができます。

microCMSのメリット・デメリット

メリット

  • フロントエンドの技術を自由に選択可能できる(React,Vue,静的ページ等)
  • サーバー管理が不要なので従来のCMSよりメンテナンス管理が容易
  • 高いパフォーマンスが期待できる
    • CDN配信によるグローバルな高速表示
    • バックエンドとフロントエンドの分離による負荷分散

デメリット

  • APIの扱いに慣れる必要があるため、バックエンド側の知識が必要
  • フロントエンドの開発スキルが求められる
  • 無料プランの制限(API呼び出し回数や機能制限)
  • WordPressなど既存CMSからの移行は容易ではない

microCMSのアカウント登録

ここから実際に設定をはじめたいと思います
以下のURLからmicroCMSアカウント登録を行います
https://microcms.io/

1.メールアドレスとパスワードを入力して登録ください
2.アンケートは任意となりますので、不要であれば「スキップ」できます

アカウントの登録が完了しました

microCMSの設定

microCMS側の設定を行っていきます

1.プロジェクトの作成

それではサービス(プロジェクト)を作成していきます
今回はオリジナルでブログのサービスを作成していくので「一から作成する」を選択

次に「サービス名」と「サービスID」を入力

サービスの作成が完了しました

2.APIの作成

次はAPIの設定をしていきます

2-1 カテゴリ

カテゴリを作成していきます
1.サイドバーのコンテンツ(API)から「+」をクリックして、APIを作成していきます

2.「API名」と「エンドポイント」を入力

3.リスト形式を選択

4.カテゴリのフィールドを設定します

5.カテゴリの登録
「+追加」からカテゴリを登録します。
複数登録すると以下のようにカテゴリ一覧ができました。

2-2 ブログ記事

次はブログ記事を設定していきます。

1.同じように「コンテンツ(API)」から、「API名」と「エンドポイント」を入力

2.リスト形式を選択し、ブログのコンテンツとなる「タイトル」「本文」「カテゴリ」を設定します


3.ブログの投稿
設定後、「タイトル」「本文」「カテゴリ」を入力し、記事を複数投稿しましょう

4.データの確認
確認のため、記事のデータが正しく送信出来ているか確認します。
一覧から詳細ページに移り「APIプレビュー」をクリック

5.PHPタブに設定して「取得」をクリック。
無事にjsonデータが送信されているのが確認できます

6.設定値の確認
LaravelとmicroCMSと連携するため、以下の設定値をメモしておきましょう。
サイドバーの歯車マークから「APIキー」をクリックし、以下の2つの値をメモ

microCMS側の設定は以上となります。

Laravel側の設定

Laravel側の設定を行います

SDK(microcms-php-sdk)のインストール

microcms-php-sdkをインストールします

composer require microcmsio/microcms-php-sdk

.env

先ほどメモした値を設定してください

MICRO_CMS_SERVICE_ID=サービスID
MICRO_CMS_API_KEY=APIキー

config/service.php

以下の情報を追加してください

'microcms' => [
    'service_id' => env('MICRO_CMS_SERVICE_ID'),
    'api_key' => env('MICRO_CMS_API_KEY'),
],

Serviceの設定

microCMS側のデータを読み込むために、サービスクラスの設定を行います
Clientクラスのインスタンスを初期化し、指定したエンドポイントから情報を取得できるようにします

app/Services/BlogService.php

<?php

namespace App\Services;

use Microcms\Client;

class MicroCmsService
{
    private Client $client;

    public function __construct()
    {
        $this->client = new Client(
            config('services.microcms.service_id'),
            config('services.microcms.api_key'),
        );
    }

    // 記事一覧を取得
    public function getList(string $endpoint, array $options = []): object
    {
        return $this->client->list($endpoint, $options);
    }

    // 特定の記事を取得
    public function getContent(string $endpoint, string $contentId, array $options = []): object
    {
        return $this->client->get($endpoint, $contentId, $options);
    }
}

BlogController

ブログ一覧、詳細ページを設定します。

Controllers/BlogController.php

namespace App\Http\Controllers;
use Illuminate\View\View;

use App\Services\BlogService;
use App\Http\Controllers\Controller;

class BlogController extends Controller
{
    private BlogService $blogService;

    /**
     * @param BlogService $blogService
     */
    public function __construct(BlogService $blogService)
    {
        $this->blogService = $blogService;
    }

    /**
     * ブログ記事一覧を表示
     */
    public function index(): View
    {
        $response = $this->blogService->getList('articles', [
            'limit' => 10,
            'orders' => ['publishedAt']
        ]);

        return view('index', [
            'blogs' => $response->contents ?? [],
            'totalCount' => $response->totalCount ?? 0
        ]);
    }
    
    /**
     * ブログ記事詳細を表示
     */
    public function show($id): View
    {
        $blog = $this->blogService->getContent('articles', $id);
        return view('show', ['blog' => $blog]);
    }

}

web.phpの設定

use App\Http\Controllers\BlogController;

// ブログ
Route::controller(BlogController::class)->group(static function () {
    Route::get('index', 'index')->name('index');
    Route::get('show/{id}', 'show')->name('show');
});

ブログ一覧の表示

resources/views/index.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
        {{-- bootstrap5 --}}
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous">
        </script>
    </head>
    <body class="font-sans antialiased dark:bg-black dark:text-white/50">
        <div class="container py-5">
            <h1 class="mb-4">ブログ記事一覧(全{{ $totalCount }}件)</h1>
        
            <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
                @foreach($blogs as $blog)
                    <div class="col">
                        <div class="card h-100 shadow-sm">
                            <div class="card-body">
                                <h2 class="card-title h5">{{ $blog->title }}</h2>
                                <p class="card-text text-muted">
                                    <i class="bi bi-calendar-event"></i> 公開日: {{ date('Y年m月d日', strtotime($blog->publishedAt)) }}
                                </p>
                                <div class="mb-3">
                                    @foreach($blog->categories as $category)
                                        <span class="badge bg-secondary me-1">{{ $category->name }}</span>
                                    @endforeach
                                </div>
                                <a href="{{ route('show', ['id' => $blog->id]) }}" class="btn btn-primary">
                                    詳細を見る <i class="bi bi-arrow-right"></i>
                                </a>
                            </div>
                        </div>
                    </div>
                @endforeach
            </div>
        </div>
    </body>
</html>

以下のように、Laravel側でブログ記事の一覧が表示されるようになりました
microCMS側で作成したブログ記事3つが表示されています

ブログ詳細の表示

resources/views/show.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
        {{-- bootstrap5 --}}
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous">
        </script>
    </head>
    <body class="font-sans antialiased dark:bg-black dark:text-white/50">
        <div class="container py-5">
            <div class="row justify-content-center">
                <div class="col-lg-8">
                    <nav aria-label="breadcrumb" class="mb-4">
                        <ol class="breadcrumb">
                            <li class="breadcrumb-item"><a href="{{ route('index') }}">ブログ一覧</a></li>
                            <li class="breadcrumb-item active" aria-current="page">{{ $blog->title }}</li>
                        </ol>
                    </nav>
        
                    <article class="blog-detail">
                        <header class="mb-4">
                            <h1 class="display-5 fw-bold">{{ $blog->title }}</h1>
                            <div class="text-muted mb-3">
                                <i class="bi bi-calendar-event"></i> 公開日: {{ date('Y年m月d日', strtotime($blog->publishedAt)) }}
                            </div>
                            <div class="mb-3">
                                @foreach($blog->categories as $category)
                                    <span class="badge bg-secondary me-1">{{ $category->name }}</span>
                                @endforeach
                            </div>
                        </header>
        
                        <div class="blog-content mb-5">
                            {!! $blog->main !!}
                        </div>
        
                        <div class="d-grid gap-2 d-md-flex justify-content-md-start">
                            <a href="{{ route('index') }}" class="btn btn-outline-primary">
                                <i class="bi bi-arrow-left"></i> 一覧に戻る
                            </a>
                        </div>
                    </article>
                </div>
            </div>
        </div>
    </body>
</html>

詳細画面の方の内容も、無事内容を取得して表示出来ています

まとめ

以上となります

microCMS側の無料プランはAPI作成が3つまでとなるため、実際にプロジェクトで活用する時は上限の考慮も必要となりそうです

Discussion