# プラグイン開発

注意: 残念ながら、このドキュメントは少し古くなっています（訳注：かなり古くなっている箇所もあります。本家のWikiやGeeklog.jpのWikiも参照してください。）。ここに記述されているAPI機能は今でも正常に機能しますが、新しい関数の中には取り上げられていないものもあります。はっきりしない場合は、プラグインインターフェースを実装している `system/lib-plugins.php` を見てください。

以下のAPIの記述が簡潔すぎると思われるなら、より広範囲をカバーするプラグイン開発者ガイドを見る必要があるでしょう。

- 概要
- GeeklogプラグインAPI関数
  - モデレーション用関数
  - 管理者及びユーザメニュー用関数
  - 検索用関数
  - コメント用関数
  - 統計用関数
  - アンインストール用関数
  - ユーザ用関数
  - プロフィール用関数
  - その他の関数
  - フィード用関数
- 独自の管理者インターフェースの実装
- プラグイン配布の準備
- プラグインのインストール方法
- プラグインの配布

## 概要

Geeklogは日々人気が高まり、独自の要求を満たすためGeeklogの機能拡張を行うためにユーザが行うハックに開発者たちは驚いています。それと同時に、開発者チームはGeeklogを改良するために絶えず新機能を追加しています。私たちはGeeklogのコアコードとプラグインの2系統をサポートする必要があることを理解しています。プラグインによってGeeklogの機能を拡張するのに必要なインフラを整備することにより、私たちはGeeklogのコアコードとプラグインを明確に分離することができます。そうすることで、私たちはコアコードの開発に、他のユーザは自分の要求にあったプラグインの開発に専念することができます。そういうわけで、GeeklogにはプラグインAPIが備わっています。

最上位のレベルで考えると、GeeklogのプラグインAPIはGeeklogのコアコードの要所要所で呼び出される汎用のコードであり、プラグインの関数を呼び出すことが可能になります。プラグインは以下の機能を与えられています。

- プラグインはユーザの投稿を受け付けることができる。管理者はコントロールパネルでプラグイン宛に投稿されたデータのモデレーションを行える。
- プラグインはGeeklogのページごとにプラグインを管理者ブロックとユーザブロックに表示することができる。
- プラグインはGeeklogの検索ページ経由でプラグインを検索対象とすることができる。
- プラグインはプラグインの統計情報をサイトの統計情報に表示することができる。
- プラグインはGeeklogのコメントエンジンを使用できる。
- プラグインは、Geeklogのコアコード(`lib-common.php`)を使用できる。
- プラグインには完全な柔軟性が与えられる。Geeklogはプラグインにあれこれ要求したりしない。

## プラグインを書くための関数

以下の関数は、必須パラメータに加えて追加パラメータを含めて独自のプラグインを書くために必要なものです。プラグインの処理を理解する必要がある場合に備えて、このページの最後付近にAPIの記述があります。

<プラグイン名> の表記に注意：以下の関数で <プラグイン名> という記述がありますが、これはプラグインのアーカイブファイル名に由来するものです（訳注：正確には、プラグイン名）。プラグインのアーカイブファイル名は以下の記法に従わなければなりません。

> <プラグイン名>_<プラグインのバージョン>_<Geeklogのバージョン>.tar.gz
> 例：`photos_1.0_1.3.tar.gz`

## モデレーション用関数

現在のGeeklogのコアコードでは、投稿物を処理するためのデータベースのテーブル名には従わなければならない規約があります。記事やリンクなどのモデレーションされるアイテムは2つのテーブルを使用します。最初のテーブルは主要なもので、公開されるすべてのアイテムが保存されます。2番目のテーブルは管理者が承認するまで投稿物が保存されるテーブルです。アイテムが承認されると、2番目のテーブルから1番目のテーブルに移されます。たとえば、ユーザの書評投稿を受け付ける書評プラグインを制作しているなら、1番目のテーブルの名前を `bookreviews` とし（また、プラグイン名も `bookreviews`としなければなりません）、2番目のテーブル名を `bookreviewssubmission` としなければなりません。このような命名を強制するのは、Geeklogのコアコードで
`2番目のテーブル名 = <1番目のテーブル名>submission`
とコーディングされているからです。ですから、プラグイン名を `bookreviews` とするなら、1番目のテーブル名は `bookreviews` 、2番目のテーブル名は `bookreviewssubmission` としなければなりません。

Geeklogの記事やリンクプラグインのように、プラグインにモデレートさせたいなら、以下の関数を実装しなければなりません。

表1. モデレーション用関数
関数名 | 関数の説明
--- | ---
plugin_submit_<プラグイン名> | プラグインの投稿フォームを表示する。
plugin_itemlist_<プラグイン名> | プラグインへ投稿されたアイテムでモデレーションを必要とするものを `moderation.php` で表示する。
plugin_savesubmission_<プラグイン名> | ユーザが投稿したアイテムを <プラグイン名>submission テーブルに保存する。
plugin_moderationdelete_<プラグイン名> | <プラグイン名>submission テーブルで該当するIDのデータを削除する。
plugin_moderationapprove_<プラグイン名> | <プラグイン名>submission テーブルで該当するIDのデータを主テーブル（<プラグイン名>）へ移す。
plugin_moderationvalues_<プラグイン名> | 主テーブル（<プラグイン名>）のプライマリキーのあるフィールド名、テーブル名、モデレーション用のページに表示したいフィールド名のリストを返す。

## 管理者及びユーザメニュー用関数

Geeklogのページごとに管理者機能ブロックとユーザ機能ブロックにプラグインを表示したいなら、以下の関数を実装しなければなりません。

表2. 管理者及びユーザメニュー用関数
関数名 | 関数の説明
--- | ---
plugin_adminoptions_<プラグイン名> | 管理者機能ブロックにプラグインのオプションを表示する。
plugin_getuseroption_<プラグイン名> | ユーザ機能ブロックにプラグインのオプションを表示する。
plugin_adminedit_<プラグイン名> | `admin/plugins/<プラグイン名>.php` のトップに「新規作成」と「管理者機能HOME」へのリンクを表示する。この関数は整合性を取るためにのみ存在する。
plugin_submissioncount_<プラグイン名> | プラグインに投稿されたアイテムで承認待ちの投稿数を表示する。ふつう、これは `"SELECT (*) FROM `<プラグイン名>submission`"` と等価の動作である。
plugin_cclabel_<プラグイン名> | プラグインのアイコンとリンクテキストの配列を返す。`moderation.php` のコントロールパネルでプラグインのデータを表示するために使用される。

## 検索用関数

プラグインのデータを検索可能にしたいなら、以下の関数を実装しなければなりません。

表3. 検索用関数
関数名 | 関数の説明
--- | ---
plugin_getsearchtypes_<プラグイン名> | `search.php` の検索タイプにプラグインに対応する新しいタイプを追加しなければならないだろう。この関数では必要とされる `<options>` タグを表示する。`value属性` は <プラグイン名> でなければならない。
plugin_dopluginsearch_<プラグイン名> | 検索条件を受け取り、プラグインの検索結果を返す。返り値はテーブルの列を文字列の配列にしたもので、1列が検索によって返される1レコードに対応するものとなっている。

## コメント用関数

プラグインがコメントをサポートし、Geeklogのコメントエンジンを使用したいなら、以下の関数をプラグインの `functions.inc` ファイル内に実装する必要があります。

表4. コメント用関数
関数名 | 関数の説明
--- | ---
plugin_commentsupport_<プラグイン名> | この関数は引数を取らない。プラグインがコメントをサポートする場合には `true` を返すだけである。この関数はGeeklogのコード内（たとえば、`article.php`）で呼び出され、コードがコメントの扱いをプラグインに委ねるかどうかが判断される。
plugin_handlecomment_<プラグイン名> | この関数はコメントID（コメント用テーブルでプライマリキーのあるフィールド）とコメントに対する操作のタイプ（'save'か'delete'のどちらか）を受け取る。プラグインのレコードのコメントの総数が更新される。それから、サイトのメインページにではなくプラグインのページにユーザをリダイレクトまたはリフレッシュする。
plugin_commentform_<プラグイン名> | この関数は多数のパラメータを受け取り、Geeklogの `article.php` と `comment.php` から呼ばれる。パラメータは、コメントID（プライマリキー）、コメントモード（nested, flat, threaded, none）、順序（昇順・降順）、返答（コメントバーの「コメントを追加」ボタンが使用されたかどうか）である。 コメントIDのみ必須である。
plugin_commentparent_<プラグイン名> | プラグインのコメントフォーム関数から親コメントを表示するために呼び出すことが可能なオプションの関数。このやり方で、Geeklogは記事と共にコメントバーと関連するコメントを表示している。

## 統計用関数

プラグインの統計情報をサイトの統計情報に表示したいなら、以下の関数を実装しなければなりません。

表5. 統計用関数
関数名 | 関数の説明
--- | ---
plugin_showstats_<プラグイン名> | この関数はshowsitestatsフラグを取る。1 に設定すると、この関数はプラグインの全般的な統計情報をサイトの統計情報ページに表示する。2 に設定すると、プラグインの詳細な統計情報を表示する（記事の中で閲覧回数の上位10位、コメント数の多い上位10位などに似た情報）。

## アンインストール用関数

自動的にアンインストールする機能をプラグインに与えるなら、以下の関数を実装しなければなりません。

表6. アンインストール用関数
関数名 | 関数の説明
--- | ---
plugin_uninstall_<プラグイン名> | この関数は引数を取らない。アンインストールを試み、データベースから該当するテーブルと情報を削除する。 アンインストールが成功したら `true` 、失敗したら `false` を返さなければならない。

## ユーザ用関数

プラグインの中には、ユーザアカウントの作成・削除を監視しなければならないものがあります。

表7. ユーザ用関数
関数名 | 関数の説明
--- | ---
plugin_user_create_<プラグイン名> | ユーザアカウントが新規作成されたとき、この関数が呼び出される。渡される唯一のパラメータはユーザIDである。 この関数は返り値を持たない。
plugin_user_delete_<プラグイン名> | ユーザアカウントが削除されたとき、この関数が呼び出される。渡される唯一のパラメータはユーザIDである。 この関数は返り値を持たない。

## プロフィール用関数

プラグインは、ユーザのプロフィールにブロックや個々の項目を追加できます。

表8. プロフィール用関数
関数名 | 関数の説明
--- | ---
plugin_profilevariablesedit_<プラグイン名> | ユーザプロフィールを編集するフォームが表示される直前に、この関数は呼び出される。パラメータとして、ユーザIDと編集用テンプレートへの参照（レファレンス）が渡される。この関数は、独自のテンプレート変数（{変数名}）と入力フィールドをテンプレートに追加できる。 この関数は返り値を持たない。テンプレートにデータを追加するには、Templateクラスのメソッド（`set_var` など）を用いる。
plugin_profileblocksedit_<プラグイン名> | ユーザプロフィールを編集するフォームが表示される直前に、この関数は呼び出される。パラメータとしてユーザIDが渡される。この関数は、ユーザプロフィールを編集するフォームに表示したいブロック（ブロックのヘッダ・フッタを含む）のHTMLを返すことができる。複数のデータを要求する場合は、こちらの関数を使って項目をグループ化した方がよいだろう。それ以外の場合は、上述の `plugin_profilevariablesedit_<プラグイン名>` を使う方がよいだろう。 この関数は、ブロックのHTMLか空文字列を返さなければならない。
plugin_profilevariablesdisplay_<プラグイン名> | ユーザプロフィールが表示される直前に、この関数は呼び出される。パラメータとして、ユーザIDと編集用テンプレートへの参照（レファレンス）を受け取る。この関数は、独自のテンプレート変数（{変数名}）をテンプレートに追加できる。 この関数は返り値を持たない。テンプレートにデータを追加するには、Templateクラスのメソッド（`set_var` など）を用いる。
plugin_profileblocksdisplay_<プラグイン名> | ユーザプロフィールが表示される直前に、この関数は呼び出される。パラメータとしてユーザIDが渡される。この関数では、ユーザプロフィールに表示したいブロックのHTMLを返すことができる。 この関数は、ブロックのHTMLか空文字列を返さなければならない。

## その他の関数

以下の関数は上記以外の用途のためのオプションの関数です。

表9. その他の関数
関数名 | 関数の説明
--- | ---
plugin_centerblock_<プラグイン名> | この関数では、サイトのセンターエリア、つまり、記事と記事の間にブロックを表示することができる。この関数は、サイトのインデックスページを表示する間に数回呼ばれる。パラメータはインデックスページのどこにセンターブロックを表示するかを指定する。 パラメータは、 `場所(where)` (1 = ページの最上部, 2 = 注目記事の後, 3 = ページの最下部)、`ページ数(page number)`、`話題ID(topic id)`である。`where` を 0 にすると、全画面表示になる（この場合、サイトのヘッダ・フッタを含めて全画面に相当するHTMLを返さなければならない）。 この関数は、ブロックのHTML（ヘッダ・フッタを含む）か空文字列を返さなければならない。
plugin_getheadercode_<プラグイン名> | サイトの `<head>` ブロックに追加するJavaScriptや `<meta>` タグを返す。 この関数では、追加のヘッダ全部を改行文字(¥n)でつないだものを返さなければならない。
plugin_templatesetvars_<プラグイン名> | 追加のテンプレート変数をセットできる。現時点では、この関数が呼ばれるのは `COM_siteHeader` と `COM_siteFooter` の中だけであるが、将来は他の場所で呼び出されるようになるだろう。渡されるパラメータは、テンプレート名とテンプレートオブジェクトへの参照（レファレンス）である。プラグインAPI側では、テンプレート名（上述の通り、現時点ではヘッダかフッタ）をチェックし、渡されたテンプレートオブジェクトのレファレンスを使用して、必要なテンプレート変数を設定する。
plugin_whatsnewsupported_<プラグイン名> | この関数と次の関数を実装することで、プラグイン独自のセクションを新着情報ブロックに表示できる。 この関数は2つの文字列から構成される配列を返す。1番目の文字列はプラグインのセクションの見出しとして、2番目の文字列はそのセクションが表示する期間（"last 2 weeks"など）として使用される。
plugin_getwhatsnew_<プラグイン名> | この関数は、新着情報ブロックに表示する新規項目の配列を返す（新規項目がない場合はその旨を表示する文字列）。
plugin_chkVersion_<プラグイン名> | プラグインではこの関数を実装し、コードのバージョンを返さなければならない。新しいバージョンを公開する前に、プラグイン利用者が容易に更新できるようにするため、プラグインの `functions.inc` に含まれるコードのバージョンを表す変数を使用するべきである（訳注：プラグインのバージョンは、`functions.inc` よりもプラグインの `config.php` 内に記述した方がメンテナンスしやすい）。Geeklog 1.3.10の時点では、このAPI関数が呼び出されるのは、インストールされているプラグインのバージョンとコードのバージョンを表示するプラグインエディタの中である。インストールされているプラグインのバージョンは、`plugins` テーブルから取り出され、プラグインのインストール・アップグレード時に更新すべきである。このAPI関数を使うと、サイト管理者は現在のプラグインのコードがインストールされているバージョンより新しいか知ることができる。プラグイン開発者は `plugins` テーブルからインストールされているバージョンを読み取り、SQLを用いたアップデートが必要かどうかや `plugins` テーブルの情報を更新してコードのバージョンに合わせるかどうかを自動的に決定することができる。
plugin_runScheduledTask_<プラグイン名> | この関数を使用すると、作業を定期的に実行することができる。（OSレベルで実行されるcronジョブと違い、）この関数が呼び出されるのはサイトに訪問者があるときだけだが、メンテナンスやクリーンアップを定期的に行う大半のプラグインにとってはそれで十分であろう。この関数が呼び出される間隔はサイトのコンフィギュレーションで設定されるので、このAPIを実装するすべてのプラグインが一度にまとめて呼び出される（訳注：したがって、時間のかかる作業を実行させると、PHPやWebサーバが時間切れになってしまう。そのような作業にはcronジョブを用いるべき。）。

## フィード用関数

以下の関数は、フィード（RSSフィード）を作成するためのオプションの関数一覧です。

表10. フィード用関数
関数名 | 関数の説明
--- | ---
plugin_getfeednames_<プラグイン名> | プラグインはフィードを作成するためのコンテンツを提供できるが、この関数では提供できるフィードコンテンツのリストを返す。たとえば、リンクプラグインはすべてのリンクに対するフィードとリンクカテゴリに対するフィードを提供する。この関数では、IDと名前をペアにした配列を返す。IDはコンテンツの種類を表すプラグイン内部で使用されるIDであり、名前はユーザに表示される名前である。
plugin_getfeedcontent_<プラグイン名> | プラグインが上述の `plugin_getfeednames_<プラグイン名>` APIでフィードのリストを返す場合、この関数を用いてフィードのコンテンツを返さなければならない。フィードのコンテンツを保持する配列と、フィードに含まれサイト上にあるそのコンテンツを指す 'link' と更新チェック用に保存される 'update_data' を返す。
plugin_feedExtensionTags_<プラグイン名> | この関数を実装することで、フィードフォーマットのトップレベルに要素を追加することができる。フィードの種類とバージョン（たとえば、RSS version 2.0）を受け取り、有効なXMLタグの配列を返す。具体例は、フィード拡張(Syndication Extensions)プラグインを見ること。
plugin_feedNSExtensions_<プラグイン名> | フィードに独自の要素を追加するプラグインは、XMLに名前空間を追加しなければならないことがある。その場合、この関数を使用して有効な名前空間の属性の配列を返さなければならない。具体例は、フィード拡張(Syndication Extensions)プラグインを見ること。
plugin_feedElementExtensions_<プラグイン名> | この関数を実装することで、フィードの項目に要素を追加することができる。フィードの種類とバージョン及びコンテンツの種類とIDを受け取り、有効なXML要素の配列を返さなければならない。具体例は、フィード拡張(Syndication Extensions)プラグインを見ること。

## 独自の管理者インターフェースの実装

GeeklogのプラグインAPIは所詮APIに過ぎないので、プラグインのコードは全部自分で書かなければなりません。私たちは、プラグインの管理者インターフェース用のスタブをしかるべき場所に配置しただけです。プラグインの管理者用ページのURLは `http://yourgeeklogdomain/admin/plugins/<プラグイン名>/` になります。

管理者用インターフェースの最初のページは `index.php` という名前で、上述のディレクトリ内になければなりません。管理者用インターフェースに複数ページを使用するかどうかは開発者に委ねられています。

管理者用ページの位置は自由に変更できないことに注意してください。全体に整合性を持たせるために、このドキュメントで触れている標準規約に従うことが重要です。

## プラグイン配布の準備

### プラグインのアーカイブファイル

Geeklogプラグインのアーカイブファイルは、次の命名規約に従うべきです。

> <プラグイン名>_<プラグインのバージョン>_<Geeklogのバージョン>.tar.gz

### 説明

<プラグイン名>：
  これはプラグイン作成時に決めなければならない最重要事項の1つです。なぜなら、このプラグイン名によって
  - Geeklogのコアコードが呼び出すAPI関数名
  - プラグイン関係のすべてのファイルを置くドキュメントツリー内の位置
  - 管理者用コードを置くadminディレクトリ内のディレクトリ名
  - モデレーションを行う場合は、主テーブルの名前
  - モデレーションを行う場合は、副テーブルの名前（主テーブル名 + submission）
  が決まるからです。
<プラグインのバージョン>：
  プラグインをインストール中に、新規インストールするのかアップグレードするのかを判断するために使用されます。インストールされているバージョンより古いバージョンをインストールしようとしていないか検証するためにも使用されます。
<Geeklogのバージョン>：
  プラグインが動作するGeeklogのバージョン。

アーカイブファイルの構成も標準化されています。ディレクトリとファイル名ごとに説明します。アーカイブファイルを作成するとき、トップのディレクトリ名は <プラグイン名> と同じにすべきです。そのディレクトリ内に以下のディレクトリ・ファイルを配置します。

config.php：
  プラグインの設定用ファイル。可能なら（Geeklog-1.5に関しては）Geeklogに組み込まれているコンフィギュレーションインターフェースを使用することをお勧めします。そちらの方がプラグインを使用する人にとっては遙かに簡単だからです。Geeklog Wikiのプラグインでコンフィギュレーションを使用する方法(how to use the configuration for a plugin)に追加情報があります。
functions.inc：
  このファイルにGeeklogのAPI関数とプラグインのコードを置くべきです。`lib-common.php` の最後の部分で、有効になっているプラグインの `functions.inc` ファイルを読み込むので、ファイル名は `functions.inc` でなければなりません。逆に言うと、プラグインのコード内では、`lib-common.php` 内のすべての関数を呼び出すことができるということです。
language/ ディレクトリ：
  プラグインの言語ファイルの置き場所。言語ファイルはプラグインの `functions.inc` の先頭で読み込むべきです。
  Geeklogの振る舞いを模倣し、ユーザが設定した言語に対応できるよう `language` ディレクトリ内に言語ファイル（`english.php` など）を置くことをお勧めします。選択した言語に対応する言語ファイルが存在しない場合は、既定の言語ファイル（`english.php`など）が選ばれます。
README
  標準的な、ソフトウェアのREADMEファイル。
/docs:
  プラグインの改訂履歴やTO-DOなどを置きます。
/admin:
  管理者用ページを置きます。
/public_html:
  標準的な、サイトを構成するファイルを置きます。
/updates:
  更新用のSQLとPHPスクリプトを置きます。

## プラグインのインストール方法

注意： Geeklog-1.3.4までは、プラグインを自動的にインストールする機構がありました。しかしながら、多くのトラブルとサポートの問題が生じたので、以降のバージョンでは廃止されています。以下に述べる手動インストールの手順がプラグインをインストールする標準的な方法で、Geeklogのバージョンを問わず機能します。

詳細は、プラグインに添付されている `README` ファイルを常に参照すべきです。プラグインの概要とインストールの詳細な手順は、Geeklogドキュメント作成プロジェクトの一環として、ここで公開されています。しかしながら、一般的には、次のようにしてプラグインをインストールします。

1. セットアップとサーバへのアクセスにもよりますが、アーカイブファイルをアップロードしてリモートで展開（伸張・解凍）するか、ローカルで展開した後でできたディレクトリとファイルをアップロードするかのどちらかです。
2. アーカイブファイル中の `public_html` は、Webサーバの公開領域の下に <プラグイン名> の名前でコピーします。たとえば、Geeklogのサイトが `/path/to/geeklog/public_html/` にある場合、アーカイブファイルの `public_html` ディレクトリの内容は `/path/to/geeklog/public_html/<プラグイン名>` の中にコピーします。
3. アーカイブファイルの `admin` ディレクトリは、管理者用エリアにコピーします。たとえば、管理者用エリアが `/path/to/geeklog/public_html/admin/` の場合、アーカイブファイルの `admin` ディレクトリの内容は、 `/path/to/geeklog/public_html/admin/plugins/<プラグイン名>` の中にコピーします。
4. プラグインのインストール用スクリプト（`http://yourgeeklogsite/admin/plugins/<プラグイン名>/install.php`）を呼び出します。
   - 新規インストールの場合（プラグインが `plugins` テーブルに存在しない場合）、インストールスクリプトは必要なSQLを発行してテーブルと初期データを作成します。
   - アップグレードの場合、提供されているプラグインのドキュメントを参照する必要があります。比較的新しいプラグインAPIはアップグレードを実行するAPIを提供しています。プラグインエディタを使用すれば、必要なら更新をブラウザから実行できます。
5. これでおしまいです!

## プラグインの配布

GeeklogのプラグインはインストールされているGeeklogやユーザのファイルシステムに影響を与える可能性があるので、開発者チームが検証したものでなければサードパーティ製のプラグインを承認しないことになっています。プラグインをきちんとインストールでき、トラブルを引き起こさないことを確認したいからです。確認できれば、開発者がアップロードしたアーカイブファイルをGeeklogユーザがダウンロードできる場所に置きます。開発したプラグインを http://www.geeklog.net/ に投稿してもよいでしょう。