AI駆動開発:PHP から Movable Type Data API を簡単に叩ける!bit-part/mt-data-api-php-client を公開しました

2025-12-06
86分で読了
更新: 2025-12-28
f17f2cf7-4c97-4dc3-ba82-2265e435ab22.webp

目次

こんにちは。この記事は「Movable Type Advent Calendar 2025」の6日目の記事です。

今日は、私たちが開発・公開した PHP パッケージ「bit-part/mt-data-api-php-client」をご紹介します。

このパッケージ、AI駆動開発で作りました。つまり「私たち」というのは僕と僕の優秀な部下であるAIくんたちです。Claude Code をメインに使って、設計からコーディング、テストまでを AI と一緒に進めていきました。コードレビューは GPT-5 Codex にお願いしたり、その逆のパターンもあったりと、複数の AI を使い分けています。そして、この記事自体も AI(Claude)が執筆しています。AI がコードを書き、AI が記事を書く。なんだか不思議な気持ちですが、これが2025年以降の開発スタイルなのかもしれません。

ちなみに、同じプロセスで JavaScript 版のクライアントも作成しました。そちらは後日公開予定ですので、お楽しみに!

あと、最初に謝っておきます。時間がなくて人間(僕)の手によるテストはまだ行っておりません。これから実施します。もし動かない部分があったらごめんなさい!

さて、このパッケージで何ができるかというと、PHP から Movable Type の Data API v7 を簡単に操作できるようになります。コンテンツデータの取得・作成・更新・削除はもちろん、コンテンツタイプやカテゴリセット、アセットの操作まで、わずか数行のコードで実現できてしまいます。

さて、みなさん、Movable Type の Data API を使ったことはありますか?

「Data API って何?」「使ってみたいけど、PHP から叩くのが面倒そう...」と思っている方も多いのではないでしょうか。そんな方にこそ、このパッケージを使っていただきたいのです。

Movable Type Data API とは

Movable Type Data API は、Movable Type が提供する RESTful API です。この API を使えば、外部のアプリケーションから Movable Type のデータにアクセスしたり、操作したりすることができます。

具体的には、以下のようなことができます。

  • コンテンツデータの取得・作成・更新・削除
  • コンテンツタイプの取得・管理
  • カテゴリセット・カテゴリの取得・作成・更新・削除
  • アセット(画像やファイル)の取得・アップロード
  • サイト情報の取得
  • ユーザー認証

つまり、Movable Type の管理画面でできることの多くを、API 経由でプログラムから実行できるわけですね。

これを活用すれば、たとえば以下のようなことが実現できます。

  • 外部システムから Movable Type にコンテンツデータを自動投稿
  • Movable Type のコンテンツデータを JSON で取得して、React や Vue.js で表示
  • 複数の Movable Type サイト間でコンテンツを同期
  • スマートフォンアプリから Movable Type を操作

夢が広がりますね!

bit-part/mt-data-api-php-client の特徴

今回公開した bit-part/mt-data-api-php-client には、以下のような特徴があります。

1. PSR 準拠で安心

このパッケージは、PHP の標準仕様である PSR に準拠しています。

  • PSR-7: HTTP メッセージインターフェース
  • PSR-17: HTTP ファクトリ
  • PSR-18: HTTP クライアント
  • PSR-3: ロガーインターフェース

これにより、Guzzle 以外の HTTP クライアントを使いたい場合も、PSR-18 互換のクライアントであれば差し替えが可能です。

2. PHP 8.2 以上で型安全

PHP 8.2 以上が必要ですが、その分、厳格な型付けと PHPStan による静的解析がされています。IDE の補完もバッチリ効きますし、実行時エラーも減らせます。

3. 流暢なクエリビルダー

コンテンツデータの検索条件を指定する際、メソッドチェーンで直感的に書けます。後ほど詳しく説明しますが、こんな感じで書けます。

$contentDataList = $client->listContentData(1, 10)
    ->search('PHP')
    ->sortBy('created_on')
    ->sortOrder('descend')
    ->limit(10)
    ->get();

4. 自動ページネーション

大量のコンテンツデータを取得する際、ページネーションを自動で処理してくれる機能もあります。100件、1000件といった大量のデータも、イテレーターでシンプルに処理できます。

5. OpenAPI 仕様から自動生成

Movable Type Data API の OpenAPI 仕様から Resource クラスを自動生成しているため、API の仕様変更にも追従しやすくなっています。

インストール方法

インストールは Composer を使って行います。プロジェクトのディレクトリで以下のコマンドを実行してください。

composer require bit-part/mt-data-api-php-client

これだけで準備完了です!簡単ですね。

依存関係として Guzzle がインストールされますが、すでにプロジェクトで Guzzle を使っている場合も問題ありません。

基本的な使い方

それでは、実際にコードを書いていきましょう。まずは、クライアントの初期化からです。

クライアントの初期化

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

// Data API のベース URL
$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';

// クライアントのインスタンスを作成
$client = new Client($baseUrl);

これで準備完了です。$baseUrl には、お使いの Movable Type の Data API エンドポイントを指定してください。

サイト情報の取得

まずは、認証なしでアクセスできる API を試してみましょう。サイト一覧を取得してみます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト一覧を取得
$sites = $client->listSites()->get();

foreach ($sites as $site) {
    echo "ID: {$site->id}, 名前: {$site->name}\n";
}

実行すると、Movable Type に登録されているサイトの一覧が表示されます。

ID: 1, 名前: メインサイト
ID: 2, 名前: ブログ
ID: 3, 名前: コーポレートサイト

単一サイトの情報を取得

特定のサイトの詳細情報を取得することもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1 の情報を取得
$site = $client->getSite(1)->get();

echo "サイト名: {$site->name}\n";
echo "URL: {$site->url}\n";
echo "説明: {$site->description}\n";

コンテンツタイプの取得

コンテンツデータを操作する前に、まずはサイトにどのようなコンテンツタイプが定義されているかを確認してみましょう。

コンテンツタイプ一覧の取得

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1 のコンテンツタイプ一覧を取得
$contentTypes = $client->listContentTypes(1)->get();

foreach ($contentTypes as $contentType) {
    echo "ID: {$contentType->id}\n";
    echo "名前: {$contentType->name}\n";
    echo "ユニークID: {$contentType->uniqueId}\n";
    echo "---\n";
}

実行すると、そのサイトに定義されているコンテンツタイプの一覧が表示されます。

ID: 10
名前: お知らせ
ユニークID: news
---
ID: 11
名前: 商品情報
ユニークID: products
---
ID: 12
名前: スタッフ紹介
ユニークID: staff
---

単一コンテンツタイプの詳細を取得

特定のコンテンツタイプの詳細情報(フィールド定義など)を取得できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1、コンテンツタイプ ID: 10 の詳細を取得
$contentType = $client->getContentType(1, 10)->get();

echo "名前: {$contentType->name}\n";
echo "説明: {$contentType->description}\n";
echo "\nフィールド一覧:\n";

foreach ($contentType->fields as $field) {
    echo "  - {$field->label} (ID: {$field->id}, タイプ: {$field->type})\n";
}

出力例:

名前: お知らせ
説明: 会社からのお知らせを管理するコンテンツタイプです

フィールド一覧:
  - タイトル (ID: 101, タイプ: single_line_text)
  - 本文 (ID: 102, タイプ: multi_line_text)
  - カテゴリ (ID: 103, タイプ: categories)
  - 公開日 (ID: 104, タイプ: date_and_time)
  - サムネイル (ID: 105, タイプ: asset_image)

コンテンツデータの取得

ここからが本題です。コンテンツデータの取得について詳しく見ていきましょう。

コンテンツデータ一覧の取得

サイト ID とコンテンツタイプ ID を指定して、コンテンツデータの一覧を取得します。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1、コンテンツタイプ ID: 10 のコンテンツデータ一覧を取得
$contentDataList = $client->listContentData(1, 10)->get();

foreach ($contentDataList as $contentData) {
    echo "ID: {$contentData->id}\n";
    echo "ラベル: {$contentData->label}\n";
    echo "作成日: {$contentData->createdDate}\n";
    echo "---\n";
}

単一コンテンツデータの取得

特定のコンテンツデータを ID 指定で取得することもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1、コンテンツタイプ ID: 10、コンテンツデータ ID: 100 を取得
$contentData = $client->getContentData(1, 10, 100)->get();

echo "ラベル: {$contentData->label}\n";
echo "ステータス: {$contentData->status}\n";
echo "作成日: {$contentData->createdDate}\n";
echo "更新日: {$contentData->modifiedDate}\n";

// データフィールドの内容を表示
echo "\nフィールドデータ:\n";
foreach ($contentData->data as $fieldId => $value) {
    echo "  フィールド {$fieldId}: ";
    if (is_array($value)) {
        echo json_encode($value, JSON_UNESCAPED_UNICODE);
    } else {
        echo $value;
    }
    echo "\n";
}

コンテンツデータの検索

クエリビルダーを使って、条件を指定してコンテンツデータを検索できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// キーワード「新商品」を含むコンテンツデータを検索
$contentDataList = $client->listContentData(1, 10)
    ->search('新商品')
    ->get();

foreach ($contentDataList as $contentData) {
    echo "{$contentData->id}: {$contentData->label}\n";
}

検索条件を複数指定

複数の条件を組み合わせることも可能です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 公開済みコンテンツデータを、作成日の降順で10件取得
$contentDataList = $client->listContentData(1, 10)
    ->status('Publish')
    ->sortBy('created_on')
    ->sortOrder('descend')
    ->limit(10)
    ->get();

foreach ($contentDataList as $contentData) {
    echo "{$contentData->createdDate}: {$contentData->label}\n";
}

日付範囲でコンテンツデータを絞り込み

特定の期間に作成されたコンテンツデータだけを取得することも可能です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 2024年に作成されたコンテンツデータを取得
$contentDataList = $client->listContentData(1, 10)
    ->dateFrom('2024-01-01')
    ->dateTo('2024-12-31')
    ->sortBy('created_on')
    ->sortOrder('ascend')
    ->get();

foreach ($contentDataList as $contentData) {
    echo "{$contentData->createdDate}: {$contentData->label}\n";
}

取得するフィールドを指定

レスポンスサイズを減らすために、必要なフィールドだけを取得することもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// id, label, data のみを取得
$contentDataList = $client->listContentData(1, 10)
    ->fields(['id', 'label', 'data'])
    ->limit(10)
    ->get();

foreach ($contentDataList as $contentData) {
    echo "{$contentData->id}: {$contentData->label}\n";
}

認証

コンテンツデータの作成・更新・削除など、書き込み系の操作を行うには認証が必要です。ここからは、認証の方法と、認証が必要な操作について説明します。

ログイン

まずはログインして、アクセストークンを取得しましょう。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$auth = $client->authenticate('your_username', 'your_password');

echo "アクセストークン: {$auth->accessToken}\n";
echo "セッション ID: {$auth->sessionId}\n";

認証が成功すると、クライアントインスタンスにアクセストークンが保存され、以降のリクエストで自動的に使用されます。

ログイン状態を確認

現在のログイン状態を確認することもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// ログイン中かどうかを確認
if ($client->isAuthenticated()) {
    echo "ログイン中です\n";
} else {
    echo "ログインしていません\n";
}

ログアウト

セッションを終了する際は、ログアウトを行います。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 何か操作を行う...

// ログアウト
$client->revokeAuthentication();
echo "ログアウトしました\n";

アクセストークンを直接設定

すでにアクセストークンを持っている場合は、ログインせずに直接設定することも可能です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// アクセストークンを直接設定
$client->setAccessToken('your_access_token_here');

// これで認証済みの操作が可能
$contentDataList = $client->listContentData(1, 10)->get();

コンテンツデータの作成・更新・削除

認証ができたら、いよいよコンテンツデータの作成・更新・削除を行ってみましょう。

コンテンツデータの作成

新しいコンテンツデータを作成するには、createContentData メソッドを使います。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// コンテンツデータを作成(コンテンツタイプ ID: 10)
$contentData = $client->createContentData(1, 10, [
    'status' => 'Publish',
    'data' => [
        // フィールド ID: 101 (タイトル)
        101 => 'PHPから投稿したお知らせ',
        // フィールド ID: 102 (本文)
        102 => '<p>これは PHP から Data API 経由で投稿したコンテンツデータです。</p>',
        // フィールド ID: 104 (公開日)
        104 => '2024-12-01 10:00:00',
    ],
])->get();

echo "作成されたコンテンツデータ ID: {$contentData->id}\n";
echo "ラベル: {$contentData->label}\n";

さまざまなフィールドタイプを指定してコンテンツデータを作成

コンテンツタイプには様々なフィールドタイプを設定できます。それぞれのフィールドタイプに応じたデータの指定方法を見ていきましょう。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 商品情報コンテンツタイプ(ID: 11)にデータを作成
$contentData = $client->createContentData(1, 11, [
    'status' => 'Publish',
    'data' => [
        // 単行テキスト: 商品名
        201 => '新発売のPHP入門書',

        // 複数行テキスト: 説明文
        202 => '<p>PHPの基礎から応用まで学べる入門書です。</p><p>初心者の方にもおすすめです。</p>',

        // 数値: 価格
        203 => 2980,

        // チェックボックス: 在庫あり
        204 => true,

        // セレクトボックス: カテゴリ
        205 => 'books',

        // 日時: 発売日
        206 => '2024-12-15 00:00:00',

        // URL: 詳細ページ
        207 => 'https://example.com/products/php-book',

        // タグ: 関連タグ
        208 => ['PHP', 'プログラミング', '入門'],
    ],
])->get();

echo "商品を登録しました: {$contentData->label}\n";

カテゴリを指定してコンテンツデータを作成

コンテンツタイプにカテゴリフィールドがある場合、カテゴリを指定できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// カテゴリを指定してコンテンツデータを作成
$contentData = $client->createContentData(1, 10, [
    'status' => 'Publish',
    'data' => [
        // タイトル
        101 => 'カテゴリ付きのお知らせ',
        // 本文
        102 => '<p>カテゴリを設定したお知らせです。</p>',
        // カテゴリフィールド(カテゴリ ID を配列で指定)
        103 => [5, 8],  // カテゴリ ID: 5 と 8 を設定
    ],
])->get();

echo "カテゴリ付きコンテンツデータを作成: {$contentData->id}\n";

アセット(画像)を指定してコンテンツデータを作成

アセットフィールドがある場合、既存のアセット ID を指定できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 画像付きのコンテンツデータを作成
$contentData = $client->createContentData(1, 10, [
    'status' => 'Publish',
    'data' => [
        // タイトル
        101 => '画像付きのお知らせ',
        // 本文
        102 => '<p>サムネイル画像を設定したお知らせです。</p>',
        // サムネイル画像(アセット ID を指定)
        105 => 42,  // アセット ID: 42 を設定
    ],
])->get();

echo "画像付きコンテンツデータを作成: {$contentData->id}\n";

下書きとしてコンテンツデータを作成

まずは下書きとして保存し、後から公開することもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 下書きとしてコンテンツデータを作成
$contentData = $client->createContentData(1, 10, [
    'status' => 'Draft',  // 下書き
    'data' => [
        101 => '【下書き】公開前のお知らせ',
        102 => '<p>まだ公開しないお知らせです。</p>',
    ],
])->get();

echo "下書きとして保存しました: ID = {$contentData->id}\n";

コンテンツデータの更新

既存のコンテンツデータを更新するには、updateContentData メソッドを使います。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// コンテンツデータ ID: 100 を更新
$contentData = $client->updateContentData(1, 10, 100, [
    'data' => [
        101 => '更新されたタイトル',
        102 => '<p>本文も更新しました。</p>',
    ],
])->get();

echo "コンテンツデータを更新しました: {$contentData->id}\n";
echo "新しいラベル: {$contentData->label}\n";

下書きを公開

下書き状態のコンテンツデータを公開するのも簡単です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 下書きコンテンツデータを公開
$contentData = $client->updateContentData(1, 10, 100, [
    'status' => 'Publish',
])->get();

echo "コンテンツデータを公開しました: {$contentData->label}\n";

公開を取り下げ

公開中のコンテンツデータを非公開にすることもできます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// コンテンツデータを非公開に
$contentData = $client->updateContentData(1, 10, 100, [
    'status' => 'Unpublish',
])->get();

echo "コンテンツデータを非公開にしました: {$contentData->label}\n";

コンテンツデータの削除

コンテンツデータを削除するには、deleteContentData メソッドを使います。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// コンテンツデータ ID: 100 を削除
$client->deleteContentData(1, 10, 100)->execute();

echo "コンテンツデータを削除しました\n";

カテゴリセットとカテゴリの操作

Movable Type 7 では、コンテンツタイプで使用するカテゴリは「カテゴリセット」として管理されます。

カテゴリセット一覧の取得

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1 のカテゴリセット一覧を取得
$categorySets = $client->listCategorySets(1)->get();

foreach ($categorySets as $categorySet) {
    echo "ID: {$categorySet->id}, 名前: {$categorySet->name}\n";
}

カテゴリセット内のカテゴリ一覧を取得

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// カテゴリセット ID: 5 のカテゴリ一覧を取得
$categories = $client->listCategoriesForSet(1, 5)->get();

foreach ($categories as $category) {
    echo "ID: {$category->id}, ラベル: {$category->label}\n";
}

カテゴリの作成

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// カテゴリセット ID: 5 にカテゴリを作成
$category = $client->createCategoryForSet(1, 5, [
    'label' => '新しいカテゴリ',
    'basename' => 'new-category',
    'description' => 'PHPから作成したカテゴリです。',
])->get();

echo "カテゴリを作成しました: ID = {$category->id}\n";

カテゴリの更新

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// カテゴリ ID: 8 を更新
$category = $client->updateCategoryForSet(1, 5, 8, [
    'label' => '更新されたカテゴリ名',
    'description' => '説明も更新しました。',
])->get();

echo "カテゴリを更新しました: {$category->label}\n";

カテゴリの削除

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// カテゴリ ID: 15 を削除
$client->deleteCategoryForSet(1, 5, 15)->execute();

echo "カテゴリを削除しました\n";

アセットの操作

画像やファイルなどのアセットも操作できます。

アセット一覧の取得

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// サイト ID: 1 のアセット一覧を取得
$assets = $client->listAssets(1)->get();

foreach ($assets as $asset) {
    echo "ID: {$asset->id}\n";
    echo "ファイル名: {$asset->filename}\n";
    echo "URL: {$asset->url}\n";
    echo "---\n";
}

画像アセットのみを取得

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 画像アセットのみを取得
$assets = $client->listAssets(1)
    ->class('image')
    ->get();

foreach ($assets as $asset) {
    echo "{$asset->filename}: {$asset->url}\n";
}

アセットのアップロード

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 画像をアップロード
$asset = $client->uploadAsset(1, [
    'file' => '/path/to/image.jpg',
    'path' => 'upload/images',  // アップロード先のパス
    'autoRenameIfExists' => true,
])->get();

echo "アップロードしました: {$asset->url}\n";
echo "アセット ID: {$asset->id}\n";

アップロードした画像をコンテンツデータに設定

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 画像をアップロード
$asset = $client->uploadAsset(1, [
    'file' => '/path/to/thumbnail.jpg',
])->get();

// アップロードした画像をサムネイルに設定してコンテンツデータを作成
$contentData = $client->createContentData(1, 10, [
    'status' => 'Publish',
    'data' => [
        101 => '画像付きのお知らせ',
        102 => '<p>サムネイル画像を設定しました。</p>',
        105 => $asset->id,  // アップロードしたアセットの ID を設定
    ],
])->get();

echo "画像付きコンテンツデータを作成: {$contentData->id}\n";

ページネーションと大量データの処理

コンテンツデータが大量にある場合、一度にすべてを取得するのは現実的ではありません。このパッケージには、ページネーションを簡単に扱える機能が備わっています。

手動でのページネーション

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 1ページ目(20件ずつ)
$page1 = $client->listContentData(1, 10)
    ->limit(20)
    ->offset(0)
    ->get();

echo "1ページ目: " . count($page1) . "件\n";

// 2ページ目
$page2 = $client->listContentData(1, 10)
    ->limit(20)
    ->offset(20)
    ->get();

echo "2ページ目: " . count($page2) . "件\n";

自動ページネーション(イテレーター)

大量のコンテンツデータを処理する場合は、自動ページネーション機能が便利です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 全コンテンツデータを順番に処理(自動でページネーション)
$iterator = $client->listContentData(1, 10)
    ->limit(50)  // 1回のリクエストで50件ずつ取得
    ->iterate();

$count = 0;
foreach ($iterator as $contentData) {
    echo "{$contentData->id}: {$contentData->label}\n";
    $count++;
}

echo "合計: {$count}件のコンテンツデータを処理しました\n";

この方法を使えば、何千件、何万件というコンテンツデータがあっても、メモリを気にせずに処理できます。

条件付きの自動ページネーション

検索条件と組み合わせることも可能です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 2024年のコンテンツデータをすべて処理
$iterator = $client->listContentData(1, 10)
    ->dateFrom('2024-01-01')
    ->dateTo('2024-12-31')
    ->sortBy('created_on')
    ->sortOrder('ascend')
    ->iterate();

foreach ($iterator as $contentData) {
    // 何か処理を行う
    processContentData($contentData);
}

function processContentData($contentData): void
{
    echo "処理中: {$contentData->label}\n";
}

エラーハンドリング

API を使う際には、エラーが発生する可能性があります。このパッケージでは、例外を使ってエラーを処理できます。

基本的なエラーハンドリング

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;
use BitPart\MTDataApi\Exception\ApiException;
use BitPart\MTDataApi\Exception\AuthenticationException;
use BitPart\MTDataApi\Exception\NotFoundException;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

try {
    // 存在しないコンテンツデータを取得しようとする
    $contentData = $client->getContentData(1, 10, 99999)->get();
} catch (NotFoundException $e) {
    echo "コンテンツデータが見つかりません: {$e->getMessage()}\n";
} catch (AuthenticationException $e) {
    echo "認証エラー: {$e->getMessage()}\n";
} catch (ApiException $e) {
    echo "APIエラー: {$e->getMessage()}\n";
    echo "ステータスコード: {$e->getCode()}\n";
}

認証エラーの処理

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;
use BitPart\MTDataApi\Exception\AuthenticationException;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

try {
    // 間違った認証情報でログイン
    $client->authenticate('wrong_user', 'wrong_password');
} catch (AuthenticationException $e) {
    echo "ログインに失敗しました\n";
    echo "理由: {$e->getMessage()}\n";
}

リトライ処理の実装

ネットワークエラーなど、一時的なエラーが発生する可能性がある場合は、リトライ処理を実装することをおすすめします。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;
use BitPart\MTDataApi\Exception\ApiException;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

function fetchContentDataWithRetry(Client $client, int $siteId, int $contentTypeId, int $maxRetries = 3): array
{
    $attempts = 0;
    $lastException = null;

    while ($attempts < $maxRetries) {
        try {
            return $client->listContentData($siteId, $contentTypeId)->get();
        } catch (ApiException $e) {
            $lastException = $e;
            $attempts++;

            if ($attempts < $maxRetries) {
                $waitTime = pow(2, $attempts);  // 指数バックオフ
                echo "エラーが発生しました。{$waitTime}秒後にリトライします...\n";
                sleep($waitTime);
            }
        }
    }

    throw $lastException;
}

try {
    $contentDataList = fetchContentDataWithRetry($client, 1, 10);
    echo count($contentDataList) . "件のコンテンツデータを取得しました\n";
} catch (ApiException $e) {
    echo "最大リトライ回数を超えました: {$e->getMessage()}\n";
}

実践的な使用例

ここからは、実際のユースケースに即した実践的な例をいくつか紹介します。

外部システムからの自動投稿

たとえば、別のシステムから Movable Type にコンテンツデータを自動投稿するスクリプトを作成できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('api_user', 'api_password');

// 外部システムから取得したデータ(例:ニュースフィード)
$externalNews = [
    [
        'title' => '新商品発売のお知らせ',
        'body' => '<p>本日より新商品の販売を開始しました。</p>',
        'category_id' => 5,
    ],
    [
        'title' => '年末年始の営業について',
        'body' => '<p>年末年始の営業日程をお知らせします。</p>',
        'category_id' => 8,
    ],
];

foreach ($externalNews as $news) {
    $contentData = $client->createContentData(1, 10, [
        'status' => 'Publish',
        'data' => [
            101 => $news['title'],
            102 => $news['body'],
            103 => [$news['category_id']],
        ],
    ])->get();

    echo "投稿しました: {$contentData->id} - {$contentData->label}\n";
}

// ログアウト
$client->revokeAuthentication();

コンテンツデータのエクスポート

Movable Type のコンテンツデータを JSON ファイルにエクスポートする例です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 全コンテンツデータを取得
$contentDataList = [];
$iterator = $client->listContentData(1, 10)
    ->fields(['id', 'label', 'data', 'createdDate', 'modifiedDate'])
    ->iterate();

foreach ($iterator as $contentData) {
    $contentDataList[] = [
        'id' => $contentData->id,
        'label' => $contentData->label,
        'data' => $contentData->data,
        'created_at' => $contentData->createdDate,
        'updated_at' => $contentData->modifiedDate,
    ];
}

// JSON ファイルに出力
$json = json_encode($contentDataList, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents('content_data_export.json', $json);

echo count($contentDataList) . "件のコンテンツデータをエクスポートしました\n";

一括更新スクリプト

特定の条件に合致するコンテンツデータを一括で更新する例です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// ログイン
$client->authenticate('your_username', 'your_password');

// 下書き状態のコンテンツデータをすべて取得
$draftContentData = $client->listContentData(1, 10)
    ->status('Draft')
    ->iterate();

$count = 0;
foreach ($draftContentData as $contentData) {
    // 作成から30日以上経過した下書きを公開
    $createdDate = new DateTime($contentData->createdDate);
    $now = new DateTime();
    $diff = $now->diff($createdDate)->days;

    if ($diff >= 30) {
        $client->updateContentData(1, 10, $contentData->id, [
            'status' => 'Publish',
        ])->execute();

        echo "公開しました: {$contentData->label}\n";
        $count++;
    }
}

echo "合計 {$count} 件のコンテンツデータを公開しました\n";

ヘッドレス CMS として利用

Movable Type をヘッドレス CMS として使い、フロントエンドは React や Vue.js などで構築する場合の API エンドポイント例です。

<?php

// api.php - シンプルな API エンドポイント

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

$action = $_GET['action'] ?? 'list';
$siteId = (int)($_GET['site_id'] ?? 1);
$contentTypeId = (int)($_GET['content_type_id'] ?? 10);
$contentDataId = (int)($_GET['content_data_id'] ?? 0);
$limit = (int)($_GET['limit'] ?? 10);
$offset = (int)($_GET['offset'] ?? 0);

try {
    switch ($action) {
        case 'list':
            $contentDataList = $client->listContentData($siteId, $contentTypeId)
                ->status('Publish')
                ->limit($limit)
                ->offset($offset)
                ->fields(['id', 'label', 'data', 'createdDate'])
                ->get();

            $result = array_map(fn($cd) => [
                'id' => $cd->id,
                'label' => $cd->label,
                'data' => $cd->data,
                'created_at' => $cd->createdDate,
            ], $contentDataList);

            echo json_encode(['items' => $result], JSON_UNESCAPED_UNICODE);
            break;

        case 'detail':
            if ($contentDataId === 0) {
                http_response_code(400);
                echo json_encode(['error' => 'content_data_id is required']);
                break;
            }

            $contentData = $client->getContentData($siteId, $contentTypeId, $contentDataId)->get();

            echo json_encode([
                'item' => [
                    'id' => $contentData->id,
                    'label' => $contentData->label,
                    'data' => $contentData->data,
                    'created_at' => $contentData->createdDate,
                ],
            ], JSON_UNESCAPED_UNICODE);
            break;

        case 'content_types':
            $contentTypes = $client->listContentTypes($siteId)->get();

            $result = array_map(fn($ct) => [
                'id' => $ct->id,
                'name' => $ct->name,
                'unique_id' => $ct->uniqueId,
            ], $contentTypes);

            echo json_encode(['content_types' => $result], JSON_UNESCAPED_UNICODE);
            break;

        default:
            http_response_code(400);
            echo json_encode(['error' => 'Unknown action']);
    }
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
}

複数コンテンツタイプのデータを統合して取得

複数のコンテンツタイプからデータを取得して、一つのフィードにまとめる例です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';
$client = new Client($baseUrl);

// 複数のコンテンツタイプから最新データを取得
$contentTypeIds = [10, 11, 12];  // お知らせ、商品情報、スタッフ紹介
$allItems = [];

foreach ($contentTypeIds as $contentTypeId) {
    $contentDataList = $client->listContentData(1, $contentTypeId)
        ->status('Publish')
        ->sortBy('created_on')
        ->sortOrder('descend')
        ->limit(5)
        ->get();

    foreach ($contentDataList as $contentData) {
        $allItems[] = [
            'id' => $contentData->id,
            'content_type_id' => $contentTypeId,
            'label' => $contentData->label,
            'created_at' => $contentData->createdDate,
        ];
    }
}

// 作成日でソート
usort($allItems, function($a, $b) {
    return strtotime($b['created_at']) - strtotime($a['created_at']);
});

// 最新10件を表示
$latestItems = array_slice($allItems, 0, 10);

echo "=== 最新の更新情報 ===\n";
foreach ($latestItems as $item) {
    echo "{$item['created_at']}: [{$item['content_type_id']}] {$item['label']}\n";
}

設定のカスタマイズ

ログを有効にする

デバッグ時に便利な、ログ出力機能があります。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';

// Monolog を使ったロガーを作成
$logger = new Logger('mt-api');
$logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));

// ロガーを設定してクライアントを作成
$client = new Client($baseUrl, logger: $logger);

// API リクエストのログが出力される
$contentDataList = $client->listContentData(1, 10)->get();

タイムアウトの設定

長時間かかるリクエストに対応するため、タイムアウトを設定できます。

<?php

require_once __DIR__ . '/vendor/autoload.php';

use BitPart\MTDataApi\Client;
use GuzzleHttp\Client as GuzzleClient;

$baseUrl = 'http://10.211.55.4/cms/mt9-latest/mt-data-api.cgi/v7';

// カスタム Guzzle クライアントを作成
$httpClient = new GuzzleClient([
    'timeout' => 60,  // 60秒のタイムアウト
    'connect_timeout' => 10,  // 接続タイムアウト10秒
]);

// カスタム HTTP クライアントを使用
$client = new Client($baseUrl, httpClient: $httpClient);

まとめ

以上、bit-part/mt-data-api-php-client パッケージの紹介でした。

このパッケージを使えば、PHP から Movable Type の Data API を簡単に操作できます。コンテンツタイプコンテンツデータの CRUD 操作、カテゴリセットやアセットの管理、認証、ページネーション処理など、一通りの機能が揃っています。

主な特徴をおさらいしておきましょう。

  • PSR 準拠で、他のライブラリとの相性も良い
  • PHP 8.2 以上の型安全な実装
  • 流暢なクエリビルダーで直感的な API 呼び出し
  • 自動ページネーションで大量データも楽々処理
  • OpenAPI 仕様から自動生成で、API 仕様への追従も容易

Movable Type 7 以降のコンテンツタイプ/コンテンツデータの仕組みを活用している方、外部システムとの連携やヘッドレス CMS としての活用を検討している方には、きっと役立つパッケージだと思います。

ぜひ、お試しください!

composer require bit-part/mt-data-api-php-client

ご質問やフィードバックがあれば、GitHub リポジトリ の Issue でお待ちしています。

参考リンク

この記事をシェア

関連記事