チュートリアル

プラグインは通常、Gravのコア機能に不足があるタスクがある場合に開発されます。

このチュートリアルでは、ボタンをクリックするとランダムなブログ記事を表示するプラグインを作成します。

同様の機能をもったプラグインは、Random という名前で存在しているので、このテストプラグインを Randomizer と呼ぶことにします。

この機能は標準では、すぐに使えませんが、プラグインを使えば簡単に提供できます。GRAV が、この機能を実現するための唯一の方法ではありません。多くの選択肢があります。ここでは、そのうちの1つを紹介します。

Randomizerプラグインの概要

  • URIが設定した「トリガー・ルート」に一致したらプラグインを有効にする。(例:/random)
  • 設定されたタクソノミのみがランダムページの一覧に含まれるようにフィルタを作成します。(例:カテゴリ: ブログ)
  • フィルタリングされた一覧からランダムなページを見つけ、それをページのコンテンツに使用するよう Grav に指示します。

簡単そうでしょう?さっそくやってみましょう

Step.1 - DevTools プラグインのインストール

このチュートリアルの以前のバージョンでは、プラグインを手動で作成する必要がありました。新しいDevToolsプラグインのおかげで、このプロセス全体を省略することができます。

新しいプラグインを作成する最初のステップは、DevTools Plugin のインストールです。これには2つの方法があります。

CLIによるインストール GPM

コマンドラインで Grav インストールのルートに移動します。

bin/gpm installdevtools

admin プラグインからインストールする

ログイン後、サイドバーから「プラグイン」セクションに移動するだけです。
右上の [+追加] ボタンをクリックします。リストの中から DevTools を探し、 [インストールボタン] をクリックします。

Step.2 - Randomizer プラグインの作成

この次のステップでは、コマンドラインを使用する必要があります。DevToolsには、新しいプラグイン作成をより簡単にする CLI コマンドがいくつか用意されています。

Gravのインストールルートから以下のコマンドを入力します。

bin/plugin devtools new-plugin

実行すると、新しいプラグインを作成するために必要な質問が表示されます。

bin/plugin devtools new-plugin
Enter Plugin Name: Randomizer
Enter Plugin Description: Sends the user to a random page
Enter Developer Name: Acme Corp
Enter Developer Email: contact@acme.co

SUCCESS plugin Randomizer -> Created Successfully

Path: /www/user/plugins/randomizer

Make sure to run `composer update` to initialize the autoloader

この時点で、新しく作成したプラグインフォルダ内のcomposer updateを 実行する必要があります。

DevTools コマンドは、この新しいプラグインがどこに作成されたかを教えてくれます。この作成されたプラグインは完全に機能しますが、望む機能を実行するロジックまで自動的に持っているわけではありませんので、ニーズに合わせて変更する必要があります。

Step.3 - プラグインの基本

修正と開発が可能な新しいプラグインが出来上がっています。プラグインを構成するものを分解して見てみます。user/plugins/randomizer フォルダを見ると、以下のようなものがあります。

.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── blueprints.yaml
├── randomizer.php
└── randomizer.yaml

これはサンプル構造ですが、いくつかのものは必須です。

機能するために必要なもの

これらの項目は重要であり、これらを含めない限り、プラグインは確実に機能しません。

  • blueprints.yaml - Grav がプラグインの情報を取得するために使用する設定ファイルです。また、プラグインの詳細を見るときに管理者が表示するフォームを定義することができます。このフォームは、プラグインの設定を保存することができます。このファイルについては、「フォーム」の章で説明しています。
  • randomizer.php - このファイルはプラグインによって名前が変わりますが、プラグインが必要とするロジックを保存するために使用することができます。プラグインのイベントフックを使って、Gravのライフサイクルのほぼすべてのポイントでロジックを実行することができます。
  • randomizer.yaml - これはプラグインが使うかもしれないオプションを設定するためにプラグインによっては使われる設定です。これは.phpファイルと同じ名前である必要があります。

リリースに必要なもの

これらの項目は、GPMでプラグインを公開する場合に必要な項目です。

  • CHANGELOG.md - Grav Changelog Format に従ってリリースの変更点を示すファイル。
  • LICENSE - ライセンスファイル。特別な必要がない限り、MIT にすべきです。
  • README.md - プラグインに関するあらゆるドキュメントを含む 'Readme' です。インストール方法、設定方法、使用方法など。

Step.4 - プラグインの設定

前の項目で説明したように、プラグインにはいくつかの設定オプションが必要なので、randomizer.yamlファイルは次のようなものにします。

enabled: true
active: true
route: /random
filters:
    category: blog

これにより、必要であれば複数のフィルターを持つことができますが、今のところ、タクソノミーカテゴリー:ブログを持つすべてのコンテンツがランダム選択の対象となるように指定しただけです。

すべてのプラグインには、enabled オプションが必要です。サイト全体の設定でこれがfalseの場合、プラグインは Grav によって決して初期化されません。すべてのプラグインはactive オプションも持っています。サイト全体の設定でこれが false の場合、各ページでプラグインを有効にする必要があります。複数のプラグインは、以下で説明するmergeConfig を使ってページのフロントマターで enabled/active をサポートすることにも注意してください。

Grav のデフォルトインストールでは、デフォルトでカテゴリと タグにタクソノミーが定義されています。この設定はuser/config/site.yamlファイルで変更することができます。

Gravの他の設定と同様に、日々の制御のためにこのデフォルトの設定に触れないことをお勧めします。必要なら、/user/config/plugins/randomizer.yaml と呼ばれるファイルにオーバーライドを作成し、カスタム設定を格納します。このプラグインが提供する randomizer.yaml は、あなたのプラグインのために賢明なデフォルトを設定することを意図しています。

Step.5 - ベースプラグインの構造

ベースとなるプラグインのクラス構造は、すでに次のようなものになっています。

<?php
namespace Grav\Plugin;

use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;

/**
 * Class RandomizerPlugin
 * @package Grav\Plugin
 */
class RandomizerPlugin extends Plugin
{
    /**
     * Composer autoload.
     *
     * @return ClassLoader
     */
    public function autoload(): ClassLoader
    {
        return require __DIR__ . '/vendor/autoload.php';
    }
}

プラグインでこれらのクラスを使用するため、いくつかの use 文を追加する必要があります。use を追加することで、各クラスの完全な名前空間をインラインで記述する必要がないため、スペースを節約し、コードをより読みやすくします。

use 文を次のように修正します。

use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;
use Grav\Common\Page\Collection;
use Grav\Common\Uri;
use Grav\Common\Taxonomy;

このクラス構成で重要なのは2つ。

  • プラグインは、PHPファイルの先頭に namespace Grav\Plugin という名前空間が必要です。
  • プラグインの名前は、プラグインの名前に末尾にPluginという文字列を加えた文字列を基本とし、Plugin を継承する必要があり、そのため RandomizerPlugin というクラス名になります。

Step.6 - Subscribed イベント

Grav は高度なイベントシステムを使用しており、最適なパフォーマンスを確保するために、すべてのプラグインは Grav によって検査され、プラグインがどのイベントにサブスクライブしているかが判断されます。

public static function getSubscribedEvents(): array
{
    return [
        'onPluginsInitialized' => [
            ['autoload', 100000], // TODO: Remove when plugin requires Grav >=1.7
            ['onPluginsInitialized', 0]
        ]
    ];
}

このプラグインでは、onPluginsInitialized イベントを購読していることを Grav に伝えます。これで、このイベント(プラグインが利用できる最初のイベント)を使って、他のイベントを購読すべきかどうかを判断することができます。

注:最初のオートロードイベントリスナーは、Grav 1.6 でのみ必要です。Grav 1.7 では自動的にこのメソッドが呼び出されます。

Step.7 - プラグインを実行するかどうかを決定する

次のステップでは、RandomizerPlugin クラスにメソッドを追加して onPluginsInitialized イベントを処理し、ユーザーが randomizer.yaml ファイルで設定したルートに移動しようとしたときのみアクティブになるようにします。現在の 'sample' プラグインのロジックを以下のように置き換えてください。

public function onPluginsInitialized(): void
{
    // 管理者用プラグインである場合は実行しない
    if ($this->isAdmin()) {
        return;
    }

    /** @var Uri $uri */
    $uri = $this->grav['uri'];
    $config = $this->config();

    $route = $config['route'] ?? null;
    if ($route && $route == $uri->path()) {
        $this->enable([
            'onPageInitialized' => ['onPageInitialized', 0]
        ]);
    }
}

まず、DIコンテナから Uriオブジェクトを取得します。これには、ルート情報を含む、現在のURIに関するすべての情報が含まれています。

config() メソッドはすでにベース Plugin の一部なので、これを使えば設定したルートの設定値を簡単に取得できます。

次に、設定されたルートと現在の URI パスを比較します。もしそれらが等しければ、私たちのプラグインが新しいイベントである onPageInitialized も応答するようにディスパッチャに指示します。

このようなアプローチをとることで、必要のない余計なコードを走らせないようにしています。このような実装が、あなたのサイトを可能な限り高速に動作させます。

Step.8 - ランダムページを表示する

このプラグインの最後のステップは、ランダムなページを表示することです。

/**
 * Send user to a random page
 */
public function onPageInitialized(): void
{
    /** @var Taxonomy $uri */
    $taxonomy_map = $this->grav['taxonomy'];
    $config = $this->config();

    $filters = (array)($config['filters'] ?? []);
    $operator = $config['filter_combinator'] ?? 'and';

    if (count($filters) > 0) {
        $collection = new Collection();
        $collection->append($taxonomy_map->findTaxonomy($filters, $operator)->toArray());
        if (count($collection) > 0) {
            unset($this->grav['page']);
            $this->grav['page'] = $collection->random()->current();
        }
    }
}
  • まず、Grav DIコンテナから Taxonomy オブジェクトを取得し、変数 $taxonomy_map に代入します。
  • 次に、プラグインの設定からフィルタの配列を取得します。この設定では、これは1つの項目を持つ配列です。['category' => 'blog'] です。
  • フィルターがあることを確認し、ページを保存するために $collection 変数に新しいコレクションを作成します。
  • フィルタに一致するすべてのページを変数 $collection に追加します。
  • Grav が知っている現在のページオブジェクトの設定を解除します。
  • 現在のページをコレクション内のランダムなアイテムに設定します。

Step.9 - 後始末

DevToolsプラグインで作成されたサンプルプラグインは、onPageContentRaw() と呼ばれるイベントを使用していました。このイベントは私たちの新しいプラグインで使われないので、関数全体を安全に削除することができます。

Step.10 - 最終的なプラグインクラス

これで、プラグインは完成です。プラグインクラスの完成形は、以下のようになります。

<?php
namespace Grav\Plugin;

use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;
use Grav\Common\Page\Collection;
use Grav\Common\Uri;
use Grav\Common\Taxonomy;

/**
 * Class RandomizerPlugin
 * @package Grav\Plugin
 */
class RandomizerPlugin extends Plugin
{
    /**
     * @return array
     *
     * The getSubscribedEvents() gives the core a list of events
     *     that the plugin wants to listen to. The key of each
     *     array section is the event that the plugin listens to
     *     and the value (in the form of an array) contains the
     *     callable (or function) as well as the priority. The
     *     higher the number the higher the priority.
     */
    public static function getSubscribedEvents(): array
    {
    return [
        'onPluginsInitialized' => [
            ['autoload', 100000], // TODO: Remove when plugin requires Grav >=1.7
            ['onPluginsInitialized', 0]
        ]
    ];
    }

    /**
     * Composer autoload.
     *
     * @return ClassLoader
     */
    public function autoload(): ClassLoader
    {
        return require __DIR__ . '/vendor/autoload.php';
    }

    public function onPluginsInitialized(): void
    {
        // Don't proceed if we are in the admin plugin
        if ($this->isAdmin()) {
            return;
        }

        /** @var Uri $uri */
        $uri = $this->grav['uri'];
        $config = $this->config();

        $route = $config['route'] ?? null;
        if ($route && $route == $uri->path()) {
            $this->enable([
                'onPageInitialized' => ['onPageInitialized', 0]
            ]);
        }
    }

    /**
     * Send user to a random page
     */
    public function onPageInitialized(): void
    {
        /** @var Taxonomy $uri */
        $taxonomy_map = $this->grav['taxonomy'];
        $config = $this->config();

        $filters = (array)($config['filters'] ?? []);
        $operator = $config['filter_combinator'] ?? 'and';

        if (count($filters) > 0) {
            $collection = new Collection();
            $collection->append($taxonomy_map->findTaxonomy($filters, $operator)->toArray());
            if (count($collection) > 0) {
                unset($this->grav['page']);
                $this->grav['page'] = $collection->random()->current();
            }
        }
    }
}

あなたがこのページの内容に従っている場合は、あなたのサイトに完全に機能する Randomizer プラグインを有効になっているはずです。ブラウザで http://yoursite.com/random にアクセスするとランダムなページが表示されるはずです。また、オリジナルのランダムプラグインは、getgrav.org サイトのプラグインダウンロードセクションから直接ダウンロードすることができます。

プラグインとページの設定を統合する

様々なプラグインで使用されている人気のあるテクニックの1つは、プラグインの設定(デフォルトまたはオーバーライドされたユーザー設定のいずれか)とページレベルの設定をマージするという概念です。これは、サイト全体の設定を行い、必要に応じて特定のページのための特定の設定を行うことができることを意味します。これはプラグインに多くのパワーと柔軟性を与えます。

Gravの最近のバージョンでは、この機能を自動的に実行するヘルパーメソッドが追加され、自分でそのロジックをコーディングする必要がなくなりました。SmartyPantsプラグインは、この機能の良い例を提供しています。

public function onPageContentProcessed(Event $event): void
{
    $page = $event['page'];
    $config = $this->mergeConfig($page);

    if ($config->get('process_content')) {
        $page->setRawContent(\Michelf\SmartyPants::defaultTransform(
            $page->getRawContent(),
            $config->get('options')
        ));
    }
}

プラグインにCLIを実装する

プラグインは、bin/plugin コマンドラインと統合してタスクを実行する機能も持っています。このような機能を実装したい場合は、プラグイン CLI のドキュメントに従うとよいでしょう。


元ページ : https://learn.getgrav.org/17/plugins/plugin-tutorial