Core Media Lab記事一覧
自動化・ツール

【脱コマンド】GoogleスプレッドシートからmicroCMSへワンクリック自動入稿する完全手順(GASコード付き)

【脱コマンド】GoogleスプレッドシートからmicroCMSへワンクリック自動入稿する完全手順(GASコード付き)

はじめに:なぜスプレッドシート×microCMSの自動入稿が必要なのか?

ヘッドレスCMS(microCMS)とモダンな静的サイトジェネレーター(AstroやNext.js)を組み合わせたメディア運営は、圧倒的な表示速度と高セキュリティ、そしてインフラ費用の削減を両立できる最強の構成です。

しかし、記事の更新頻度を上げようとしたとき、多くの個人ブロガーや運営者が次の「運用の壁」に直面します。

  • 手動管理・コピペの消耗: 記事の下書きをGoogleドキュメントやスプレッドシートで管理しているのに、入稿作業のためだけにmicroCMSの管理画面を開き、見出しや本文、メタディスクリプションを1つずつ手動でコピペするのが地味に面倒で時間がかかる。
  • Gitコマンド(CLI)のハードル: MarkdownファイルをGitでプッシュする方式の場合、黒い画面(ターミナル)を開く必要があり、外出先やスマホからの修正、非エンジニアへの外注・分業が困難になる。
  • 執筆とデータ管理の分断: タイトル、スラッグ、カテゴリ、公開状態の管理表と、実際の入稿データが別々の場所にあることで、更新漏れや二重投稿などのヒューマンエラーが発生しやすい。

この問題を一撃で解決するのが、「Googleスプレッドシート + Google Apps Script(GAS)」による完全自動入稿パイプラインです。

スプレッドシートにタイトルや本文を入力し、上部メニューに追加された「🚀 自動入稿」ボタンをワンクリックするだけで、microCMSへの下書き保存や本番公開が一瞬で完了します。本記事では、無料プランの制約を回避する設定からコピペで動く完全版GASコード、実際に遭遇したエラーの突破法まで完全解説します。

ステップ1:microCMSのAPIキー権限を設定する(無料プランの注意点)

自動化スクリプトを作成する前に、まずはmicroCMS側で「GASからのAPI書き込み通信を受け付ける許可」を与える必要があります。

ここで最初に知っておくべき無料プラン特有の重要な制約があります。

無料プランの罠:新しいAPIキーは追加できない

microCMSの無料プラン(Freeプラン)では、APIキーを複数作成して用途ごとに権限を分ける機能(複数キー運用)が制限されています。管理画面で新規APIキーを作成しようとすると、有料プランへのアップグレード画面が表示されてしまいます。

解決策:既存の「default」キーの権限を拡張する

しかし、有料プランに課金することなく費用0円のままで解決可能です。プロジェクト作成時に最初から用意されている「default」キーの権限設定を変更します。

  1. microCMSの管理画面にログインし、左メニューの「サービス設定」>「APIキー」を開きます。
  2. 一覧にある default キーをクリックして設定画面を開きます。
  3. 対象のAPI(ブログAPI)に対して、以下の4つの権限すべてにチェックを入れます。
    • GET:記事取得用(サイト側のビルドで必須)
    • POST:新規記事作成用(ID自動生成時)
    • PUT:ID(slug)を指定した新規作成用
    • PATCH:既存記事の更新・上書き用
  4. 右下の「変更する」をクリックして保存し、表示されているAPIキー文字列をコピーしておきます。

注意: 既存のGET権限を残したままPOST/PUT/PATCHを追加するだけなので、現在稼働しているCloudflare PagesやAstroサイトのビルドが壊れることはありません。

ステップ2:スプレッドシートのカラム設計とGAS連携

次に、入稿管理を行うGoogleスプレッドシートを作成し、自動連携スクリプトを配置します。

スプレッドシートの列設計

スプレッドシートの1行目(ヘッダー)に、以下の列を左から順に配置します。

列 項目名 役割・入力内容
A列 コンテンツID(slug) 記事URLの末尾になる半角英数字(例:spreadsheet-gas-microcms-auto-post)
B列 タイトル 記事のタイトル(必須)
C列 メタディスクリプション 検索結果に表示される120文字程度の要約文
D列 本文(content) 記事本文(HTMLタグまたはテキスト)
E列 カテゴリID microCMSのカテゴリAPIで設定したコンテンツID(例:automation)
F列 公開状態 「下書き」または「公開」を指定
G列 ステータス 実行結果(「完了 (下書き)」「エラー: HTTP 400」などをGASが自動書き込み)
H列 公開URL/ID microCMS側のコンテンツIDや詳細エラー(GASが自動書き込み)

コピペで動く完全版GASスクリプト

スプレッドシートの上部メニュー「拡張機能」>「Apps Script」を開き、以下のコードをそのまま貼り付けます。4行目の API_KEY に先ほどコピーしたキーを入力して保存(Ctrl + S)してください。

/**
 * Core Media Lab - microCMS 自動入稿スクリプト(PUT/PATCH自動判定・フェイルセーフ版)
 */
const CONFIG = {
  SERVICE_DOMAIN: 'my-tech-media', // microCMSのサービスドメイン
  ENDPOINT: 'blogs',               // エンドポイント名(※複数形に注意)
  API_KEY: 'YOUR_API_KEY_HERE'     // microCMSのAPIキー(defaultキー)
};

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('🚀 自動入稿')
    .addItem('選択中の行を投稿 / 更新', 'publishSelectedRow')
    .addItem('全行の一括下書き投稿', 'publishAllDrafts')
    .addToUi();
}

function publishSelectedRow() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const rowIndex = sheet.getActiveCell().getRow();
  
  if (rowIndex === 1) {
    SpreadsheetApp.getUi().alert('ヘッダー行は投稿できません。');
    return;
  }
  
  processRow(sheet, rowIndex);
}

function publishAllDrafts() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow();
  
  if (lastRow < 2) return;
  
  for (let r = 2; r <= lastRow; r++) {
    const status = sheet.getRange(r, 7).getValue();
    if (!status || status.toString().indexOf('完了') === -1) {
      processRow(sheet, r);
    }
  }
  SpreadsheetApp.getUi().alert('一括処理が完了しました!');
}

function processRow(sheet, row) {
  const customId = sheet.getRange(row, 1).getValue().toString().trim(); // A列: slug
  const title = sheet.getRange(row, 2).getValue().toString().trim();    // B列: title
  const description = sheet.getRange(row, 3).getValue().toString().trim(); // C列: description
  const content = sheet.getRange(row, 4).getValue().toString();        // D列: content
  const categoryId = sheet.getRange(row, 5).getValue().toString().trim(); // E列: category
  const publishType = sheet.getRange(row, 6).getValue().toString().trim(); // F列: 公開状態
  
  if (!title) {
    sheet.getRange(row, 7).setValue('エラー: タイトル必須');
    return;
  }

  const payload = {
    title: title,
    description: description,
    content: content,
    noindex: false
  };

  if (categoryId) {
    payload.category = categoryId;
  }

  const isDraft = (publishType !== '公開');
  const baseUrl = `https://${CONFIG.SERVICE_DOMAIN}.microcms.io/api/v1/${CONFIG.ENDPOINT}`;
  
  // 新規PUT送信を試行
  let targetUrl = customId ? `${baseUrl}/${customId}` : baseUrl;
  let method = customId ? 'put' : 'post';
  if (isDraft) {
    targetUrl += `?status=draft`;
  }

  let options = {
    method: method,
    headers: {
      'Content-Type': 'application/json',
      'X-MICROCMS-API-KEY': CONFIG.API_KEY
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  try {
    let response = UrlFetchApp.fetch(targetUrl, options);
    let code = response.getResponseCode();
    let resText = response.getContentText();

    // 既に存在して「Content is already exists」が返ってきた場合は自動でPATCHに切り替えて再送
    if (code === 400 && resText.indexOf('Content is already exists') !== -1) {
      options.method = 'patch';
      response = UrlFetchApp.fetch(targetUrl, options);
      code = response.getResponseCode();
      resText = response.getContentText();
    }

    if (code === 200 || code === 201) {
      const resJson = resText ? JSON.parse(resText) : {};
      const contentId = resJson.id || customId;
      sheet.getRange(row, 7).setValue(`完了 (${isDraft ? '下書き' : '公開'})`);
      sheet.getRange(row, 8).setValue(contentId);
    } else {
      sheet.getRange(row, 7).setValue(`エラー: HTTP ${code}`);
      sheet.getRange(row, 8).setValue(resText);
    }
  } catch (e) {
    sheet.getRange(row, 7).setValue('通信エラー: ' + e.message);
  }
}

ステップ3:【実録】実装時につまずいたエラーとトラブルシューティング

実際にこのシステムを構築・疎通する過程で直面した、リアルなエラーと具体的な解決法を共有します。

1. エラー:HTTP 401(Unauthorized)

{"message":"X-MICROCMS-API-KEY is invalid."}

原因: APIキーの認証失敗です。コード全体をコピペした際に API_KEY: 'YOUR_API_KEY_HERE' の初期状態に戻っていたり、キーの前後に余分な空白スペースやクォーテーションのミスがあると発生します。

対処法: microCMSのAPIキー画面で「コピー」アイコンを確実にクリックし、GASのシングルクォーテーションの間に余白なく貼り付け直してください。

2. エラー:HTTP 404(Not Found)

原因: APIエンドポイントのURLミスです。microCMSでAPIを作成した際、エンドポイント名が単数形の blog ではなく複数形の blogs で作られているケースが多く、存在しないURLへリクエストが飛ぶことで発生します。

対処法: microCMSの「API設定」>「基本情報」で実際のエンドポイント名を確認し、GASの CONFIG.ENDPOINT を完全一致(例:blogs)させてください。

3. エラー:HTTP 400(Content already exists)

{"message":"Content is already exists. If you want update, please use PATCH request."}

原因: microCMSのAPI仕様によるものです。ID(slug)を指定して新規作成する場合は PUT ですが、既に登録済みの記事を修正・上書きする場合は PATCH で送信しなければならないという厳密なルールがあります。

対処法: 上記の完成版コードには、PUTで送信して「Content is already exists」エラーが返ってきた瞬間に自動で PATCH に切り替えて即座に再送する「自動フォールバック機能」を組み込んでいます。これにより、利用者が「新規か更新か」を意識することなく、同じボタンを押すだけで安全に反映されます。

ステップ4:WebhookとCloudflare Pagesの自動デプロイ確認

入稿データの反映が確認できたら、microCMSのWebhook通知機能を利用してフロントエンド(Cloudflare Pages)と連携します。

コンテンツの「公開」または「更新」をトリガーにWebhookがCloudflare Pagesへ自動通知を送り、Jamstackのビルドが自動実行されます。数分後には本番サイトへ最新記事が反映されるため、サーバーの操作やコマンド入力は一切不要の「完全手放し運用」が実現します。

まとめ:手作業を極限まで減らして運用の自動化へ

GoogleスプレッドシートとGAS、そしてmicroCMSを組み合わせることで、執筆管理とCMS入稿の二重作業を完全に撤廃することができました。

さらに今後は、記事slugに合わせたアイキャッチ画像({slug}.png)の自動生成や、SNS(Xなど)への自動告知投稿パイプラインを統合していくことで、メディア運用の自動化をより一層加速させていきます。