
「学校のポータルサイトに、職員朝会で使う簡単な連絡掲示板が欲しい…」
「ITが苦手な先生でも直感的に使えて、しかも無料で作りたい…」
そんな悩みを抱える学校のICT担当の先生方へ。
この記事では、Googleの無料ツールだけを使って、高機能な「職員連絡掲示板」を自作する方法を、手順を追って徹底解説します。プログラミングの経験がなくても、コードをコピー&ペーストしていくだけで完成できますので、ぜひ挑戦してみてください。
これで業務効率化!完成する掲示板のイメージ
最終的に、Googleサイトに以下のような掲示板を埋め込みます。
- アコーディオン形式: タイトルをクリックすると詳細が開きます。
- 日付表示: いつの連絡事項かが一目でわかります。
- 削除機能: 不要になった連絡を誰でも削除できます。
- 簡単入力: 専用の入力フォームから誰でも簡単に投稿できます。

システムの全体像
この掲示板は、以下の4つの無料Googleツールを連携させて作ります。
- 入力: Googleフォーム
先生方が連絡事項を書き込む「入り口」です。 - データ保存: Googleスプレッドシート
フォームから投稿されたデータが自動で記録される「台帳」です。 - 処理・表示: Google Apps Script (GAS)
スプレッドシートのデータを読み取り、見やすい掲示板の見た目(HTML)を自動生成する「頭脳」です。 - 公開場所: Googleサイト
完成した掲示板を埋め込んで、みんなが見られるようにする「壁」です。
作成手順マニュアル
それでは、実際に作成していきましょう!
ステップ1:入力フォームとデータ保存場所の準備
まず、先生方が連絡事項を入力する「入り口」となるフォームを作成します。
- Googleフォームを新規作成
Googleドライブで「新規」>「Googleフォーム」を選択し、新しいフォームを作成します。フォームのタイトルを「職員朝会 連絡フォーム」など、分かりやすい名前に変更しましょう。 - 質問項目を設定
以下の3つの質問を作成してください。- 担当者名: 種類は「記述式」、右下の「必須」をオンタイトル: 種類は「記述式」、「必須」をオン連絡内容: 種類は「段落」
- 回答の保存先としてスプレッドシートを作成
フォームの編集画面で、上部にある「回答」タブをクリックします。次に、緑色のスプレッドシートのアイコンをクリックし、「新しいスプレッドシートを作成」を選択して「作成」ボタンを押します。 - 準備完了!
新しいタブで、フォームと連携したスプレッドシートが自動で開きます。このスプレッドシートが、掲示板のデータ元になります。これで土台の準備は完了です!

ステップ2:頭脳の作成(GASコードの記述)
次に、掲示板の見た目を作り出すプログラムを書いていきます。

- 先ほど作成されたスプレッドシートのメニューから 拡張機能 > Apps Script を開きます。
- GASエディタが開いたら、2つのファイル(コード.gs と index.html)を準備します。
1. コード.gs の作成

コード.gs(最初からあるファイル)の中身を一度すべて削除し、以下のコードをそのまま貼り付けてください。codeJavaScript
/**
* スプレッドシートのデータを読み取り、アコーディオン形式の掲示板HTMLを生成するWebアプリです。
* ★★★ 誰でも使える削除ボタン機能を追加したバージョン ★★★
*/
function doGet() {
// =========================================================================
// ▼▼▼ 設定項目 ▼▼▼
// =========================================================================
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
const COLUMN_TIMESTAMP = 1;
const COLUMN_STAFF_NAME = 2;
const COLUMN_TITLE = 3;
const COLUMN_CONTENT = 4;
// =========================================================================
// ▲▲▲ 設定はここまで ▲▲▲
// =========================================================================
if (sheet.getLastRow() < 2) {
return HtmlService.createHtmlOutput("<p>まだ連絡事項はありません。</p>");
}
const data = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn()).getValues();
// HTMLテンプレートを作成し、そこにデータを埋め込む
let template = HtmlService.createTemplateFromFile('index');
template.data = data.map((row, index) => {
// スプレッドシートの行番号は2から始まるので、indexに2を足す
const rowNum = index + 2;
return {
rowNum: rowNum,
timestamp: row[COLUMN_TIMESTAMP - 1],
staffName: row[COLUMN_STAFF_NAME - 1],
title: row[COLUMN_TITLE - 1],
content: row[COLUMN_CONTENT - 1]
};
}).reverse(); // 新しい投稿が上に来るように配列を逆順にする
return template.evaluate();
}
/**
* [サーバー側関数] 指定された行を削除する関数
* HTML側のJavaScriptから呼び出される
* @param {number} rowNum - 削除する行番号
*/
function deleteRow(rowNum) {
try {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sheet.deleteRow(rowNum);
return "成功"; // 成功したことを返す
} catch (e) {
return "エラー: " + e.message; // エラーメッセージを返す
}
}
/**
* [サーバー側関数] 日付を整形するヘルパー関数
* HTMLテンプレートから呼び出すためにGAS側に配置
*/
function formatDate(date) {
return Utilities.formatDate(new Date(date), "JST", "M/d");
}
/**
* [サーバー側関数] HTMLをエスケープするヘルパー関数
* HTMLテンプレートから呼び出すためにGAS側に配置
*/
function escapeHtml(str) {
if (typeof str !== 'string') return '';
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
}
2. index.html の作成

次に、GASエディタ左側の「ファイル」の横の「+」を押し、「HTML」を選択します。ファイル名に index と入力して作成し、中身を一度すべて削除してから、以下のコードをそのまま貼り付けてください。codeHtml
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
/* CSSスタイル */
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; padding: 10px; }
.item-container { position: relative; } /* 削除ボタンの配置基準 */
.accordion { background-color: #f1f1f1; color: #444; cursor: pointer; padding: 16px; width: 100%; text-align: left; border: none; outline: none; transition: 0.4s; margin-top: 8px; border-radius: 5px; font-size: 16px; box-sizing: border-box; padding-right: 50px; /* 削除ボタンのスペース確保 */ }
.active, .accordion:hover { background-color: #e2e2e2; }
.panel { padding: 0 18px; background-color: white; max-height: 0; overflow: hidden; transition: max-height 0.3s ease-out; border-left: 1px solid #ddd; border-right: 1px solid #ddd; border-bottom: 1px solid #ddd; border-radius: 0 0 5px 5px; }
.panel pre { white-space: pre-wrap; word-wrap: break-word; font-family: inherit; font-size: 15px; margin-top: 15px; margin-bottom: 15px; line-height: 1.6; }
.delete-button { position: absolute; top: 18px; right: 15px; background: none; border: none; font-size: 20px; cursor: pointer; color: #aaa; padding: 5px; }
.delete-button:hover { color: #f44336; }
</style>
</head>
<body>
<!-- スプレッドシートのデータをループで表示する -->
<? data.forEach(item => { ?>
<div class="item-container" id="item-<?= item.rowNum ?>">
<button class="accordion">[<?= formatDate(item.timestamp) ?>] <?= item.title ?>(担当:<?= item.staffName ?>)</button>
<!-- 削除ボタン -->
<button class="delete-button" onclick="confirmDelete(<?= item.rowNum ?>, '<?= item.title ?>')">×</button>
<div class="panel">
<? if (item.content) { ?>
<pre><?= escapeHtml(item.content) ?></pre>
<? } else { ?>
<pre>(詳細な連絡内容はありません)</pre>
<? } ?>
</div>
</div>
<? }) ?>
<script>
// アコーディオンを開閉する処理
var acc = document.getElementsByClassName("accordion");
for (var i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function(event) {
if (event.target.classList.contains('accordion')) {
this.classList.toggle("active");
var panel = this.nextElementSibling.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
}
});
}
// 削除ボタンが押されたときの処理
function confirmDelete(rowNum, title) {
event.stopPropagation();
var confirmation = confirm("「" + title + "」\nこの連絡事項を本当に削除しますか?");
if (confirmation) {
document.getElementById('item-' + rowNum).style.opacity = '0.5';
google.script.run
.withSuccessHandler(onDeleteSuccess)
.withFailureHandler(onDeleteFailure)
.deleteRow(rowNum);
}
}
// 削除が成功したときの処理
function onDeleteSuccess(response) {
location.reload();
}
// 削除が失敗したときの処理
function onDeleteFailure(error) {
alert("削除に失敗しました: " + error.message);
location.reload();
}
</script>
</body>
</html>
ステップ3:掲示板の公開(Webアプリとしてデプロイ)
書いたプログラムを、インターネット上で動く「Webアプリ」として公開します。
- GASエディタの右上の青い「デプロイ」ボタンを押し、「新しいデプロイ」を選択します。
- 左上の歯車アイコン⚙を押し、「ウェブアプリ」を選択します。
- 【最重要】 以下の設定を確認・変更してください。
- 説明: 職員連絡掲示板(初回デプロイ)など
- 次のユーザーとして実行: 自分
- アクセスできるユーザー: 全員 (または、学校のGoogle Workspaceドメイン内の全員)
- 「デプロイ」ボタンを押し、権限の承認を求められたら許可を進めます。
- 完了画面に表示される「ウェブアプリのURL」をコピーします。これが掲示板のアドレスになります。

ステップ4:Googleサイトへの埋め込み
いよいよ最後の仕上げです。完成した掲示板をポータルサイトに設置します。
- Googleサイトの編集画面を開きます。
- 入力フォームへのボタンを設置
右側メニューから「ボタン」を挿入し、名前を「新しい連絡事項を登録」などにします。リンクにはステップ1で作成したGoogleフォームの共有URLを貼り付けます。(共有URLはフォーム編集画面右上の「送信」ボタンから取得できます) - 掲示板本体を埋め込む
右側メニューから「埋め込み」>「URLで埋め込む」を選択し、ステップ3でコピーしたウェブアプリのURLを貼り付けます。 - サイズを調整し、サイトを「公開」すれば、すべての作業が完了です!

運用とトラブルシューティング
- 連絡事項の追加: サイトの「登録ボタン」からフォームに入力するだけです。
- 連絡事項の削除: 掲示板の項目の右端の「×」ボタンを押します。
- Q. 変更が反映されない!
A. GASコードを修正した場合は、必ず**再度「新しいデプロイ」**を行ってください。 - Q. エラーが出た場合の対処方法!
A. TypeError: Cannot read properties of null というエラーが出た場合は、GASがスプレッドシートを見つけられていない証拠です。GASは一番左のシートを読みに行く設定なので、「フォームの回答 1」シートが一番左にあるか確認してください。
おわりに
以上で、無料で高機能な職員連絡掲示板の完成です。
このマニュアルが、あなたの学校の業務効率化、そしてDX推進の一助となれば幸いです。GASコードのCSS部分を書き換えればデザインの変更も可能ですので、ぜひあなたの学校に合わせてカスタマイズしてみてください!


コメント