メニュー

拡張

このページでは、管理パネルの拡張方法や、その際のベストプラクティスを解説します。

管理パネルテーマを理解する

普通の Grav テーマを拡張したり、修正したりするのとちょうど同じように、管理パネルの構造や見た目をテンプレートで上書きできます。
つまり、デフォルトのテンプレートの代わりに、あなたのプラグインで定義したテンプレートで、管理パネルのテーマを表示できます。
たとえば、左側にあるサイドバーナビゲーションのアバターを変更したいと思ったら、 nav-user-avatar.html.twig を変更することで可能です。

管理パネルプラグインでは、テンプレートへの path は: user/plugins/admin/themes/grav/templates のフォルダ以下に、 ADMIN_TEMPLATES として参照されます。
見つけたいファイルは、 ADMIN_TEMPLATES/partials/nav-user-avatar.html.twig にある、 <img src="https://www.gravatar.com/avatar/{{ admin.user.email|md5 }}?s=47" /> です。

あなたのプラグインの中では、テンプレートへの path は: user/plugins/myadminplugin/admin/themes/grav/templates のフォルダ以下に、 PLUGIN_TEMPLATES として参照されます。
対応ファイルは、 PLUGIN_TEMPLATES/partials/nav-user-avatar.html.twig であり、 <img src="{{ myadminplugin_avatar_image_path }}" /> のような内容になります。

このように、テンプレートの path を、非破壊的に上書きします。
関連するテンプレートだけを対象とします。
不要なテンプレートを上書きしてしまったり、他の管理テーマが同じ用途で代替テンプレートを登録してしまうのを防ぎます。
そのため、次のようにプラグインに path を登録します:

public static function getSubscribedEvents(): array
{
    return [
        'onAdminTwigTemplatePaths' => ['onAdminTwigTemplatePaths', 0]
    ];
}

public function onAdminTwigTemplatePaths($event): void
{
    $paths = $event['paths'];
    $paths[] = __DIR__ . '/admin/themes/grav/templates';
    $event['paths'] = $paths;
}

重要なことなので忘れないでほしいのですが、管理プラグインで使われるテーマは、利用可能なテンプレートに強く影響されます。
一般論として、テンプレート修正は 影響の少ない 変更に留めるべきで、あなたのプラグインをインストールしたユーザーのインターフェースを壊すことの無いようにしてください。
この意味では、 nav.html.twig よりも nav-user-avatar.html.twig を上書きした方が良いでしょう。
nav.html.twig の方が機能が豊富ですが、 {% include 'partials/nav-user-details.html.twig' %} を使って、 nav-user-avatar.html.twig をインクルードしているからです。

[!訳注]
nav-user-avatar.html.twig は、 nav-user-details.html.twig のタイポかな? と思います。

[!Tip]
管理パネルのテンプレートファイルは、自動エスケープが有効になっています。HTML コンテンツのエスケープのために |e フィルターを追加する必要はありません。しかし、適正な HTML を入力するには |raw を追加する必要はあります。

カスタムフィールドを追加

カスタムフィールドを作成するために、 PLUGIN_TEMPLATES/forms/fields/myfield へ追加します。
myfield フォルダには、その入力欄の処理方法を決める Twig テンプレートが必要です。
フィールドを追加する最も簡単な方法は、 ADMIN_TEMPLATES/forms/fields から似ているフィールドを探し、それをコピーし、その構造を理解することです。
たとえば、 HTML range スライダーを追加するには、 PLUGIN_TEMPLATES/forms/fields/range/range.html.twig を作成します。このファイルに、以下を記入します:

{% extends "forms/field.html.twig" %}

{% block input_attributes %}
    type="range"
    {% if field.validate.min %}min="{{ field.validate.min }}"{% endif %}
    {% if field.validate.max %}max="{{ field.validate.max }}"{% endif %}
    {% if field.validate.step %}step="{{ field.validate.step }}"{% endif %}
    {{ parent() }}
{% endblock %}

ここでは、 “range” という名前のフィールドタイプを、 range の input type で追加しています。
これにより、ユーザーは ボタンをスライドすることで 値を選択できます。
ブループリントで新しいフィールドを使うには、 blueprints.yaml に以下を追加するだけです:

form:
  fields:
    radius:
      type: range
      label: Radius
      id: radius
      default: 100
      validate:
        min: 0
        max: 100
        step: 10

これにより、デフォルト値が100で、0から100の値を取りうる、ステップが10のスライダーが提供されます。

このフィールドは、 prependappend ブロック利用して、さらに拡張できます。
たとえば、選択した値について、視覚的に見えるインジケーターを追加することができます。
次のように、 range.html.twig を変更します:

{% extends "forms/field.html.twig" %}

{% block input_attributes %}
    type="range"
    style="display: inline-block;vertical-align: middle;"
    {% if field.id is defined %}
        oninput="{{ field.id }}_output.value = {{ field.id }}.value"
    {% endif %}
    {% if field.validate.min %}min="{{ field.validate.min }}"{% endif %}
    {% if field.validate.max %}max="{{ field.validate.max }}"{% endif %}
    {% if field.validate.step %}step="{{ field.validate.step }}"{% endif %}
    {{ parent() }}
{% endblock %}
{% block append %}
  {% if field.id is defined %}
    <output
        name="{{ (scope ~ field.name)|fieldName }}"
        id="{{ field.id }}_output"
        style="display: inline-block;vertical-align: baseline;padding: 0 0.5em 5px 0.5em;"
    >
    {{ value|join(', ')|e('html_attr') }}
    </output>
  {% endif %}
{% endblock append %}

このように、 <output> タグを追加し、選択した値を保持します。
そしてこのタグとフィールド自体に、それらをきれいに並べるための、シンプルなスタイルを追加します。
また、フィールドに oninput 属性を追加することで、値が変化すると自動で <output> タグ内の値が更新されるようになります。
このためには、 range-slider を利用する各フィールドに、一意の id プロパティを持つ必要があります。
上記の例で id: radius としたように。
これは競合を避けるため、 id: myadminplugin_radius のようにすべきです。

[!Info]
この新しいテンプレートがフロントエンドと管理パネル(たとえば、 PLUGIN_TEMPLATES フォルダで利用)で共有される場合、すべての変数を |e でエスケープする必要があります。かわりに、 Configuration > Twig Templating > Autoescape variables で、 Yes にすることもできます。

カスタムページテンプレートを作成

テーマの基本 で言及したとおり、 Grav 内の pages 間には直接的な結びつきがあり、 Twig テンプレートファイル はテーマやプラグインで提供されます。
カスタムページテンプレートを作成するには、管理パネルプラグイン用のフィールドを定義したブループリントファイルと、コンテンツをレンダリングするテンプレートファイルを用意する必要があります。

テーマやプラグインにカスタムページテンプレートを追加

テーマやプラグインのルートフォルダに、 templates という名前のフォルダを作成してください。
このフォルダ内に、新たに mypage.html.twig ファイルを作成します。
これは、 “mypage” という新しいページテンプレートになります。

mypage.html.twig の具体例:

{% extends 'partials/base.html.twig' %}

{% block content %}
    {{ page.header.newTextField|e }}
    {{ page.content|raw }}
{% endblock %}

Twig テーマに関してより詳しい情報は、 Twig 入門 セクションにあります。

テーマは、自動でテーマの template フォルダ内にあるテンプレートファイルを探します。
もしテンプレートをプラグイン経由で追加する場合、 onTwigTemplatePaths イベントでテンプレートを追加する必要があります:

public function onPluginsInitialized(): void
{
    // If in an Admin page.
    if ($this->isAdmin()) {
        return;
    }
    // If not in an Admin page.
    $this->enable([
        'onTwigTemplatePaths' => ['onTwigTemplatePaths', 1],
    ]);
}

/**
 * Add templates directory to twig lookup paths.
 */
public function onTwigTemplatePaths(): void
{
    $this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
}

テーマやプラグインにカスタムページブループリントを追加

管理パネルプラグインに新しく mypage ページオプションを提供するため、テーマやプラグインのルートディレクトリに、 blueprints というフォルダを作成してください。
このフォルダ内で、新たに mypage.yaml ファイルを作成します。
ここでは、新しくページを作成する際に、管理パネルプラグインで表示されるカスタムフィールドを定義できます。
利用可能なフォームフィールドは、 フォーム の章で解説しています。

以下の mypage.yaml ブループリントの例では、デフォルトのページテンプレートを拡張し、コンテンツのタブに、 header.newTextField を追加しています:

title: My Page Blueprint
'@extends':
    type: default
    context: blueprints://pages

form:
  fields:
    tabs:
      type: tabs
      active: 1
      fields:
        content:
          type: tab
          fields:
             header.newTextField:
              type: text
              label: 'New Text Field'

templates フォルダと同様に、テーマは blueprints フォルダ内のブループリント yaml ファイルを自動で追加します。
プラグイン経由で追加されるブループリントは、 onGetPageTemplates イベントで追加する必要があります。

public function onPluginsInitialized(): void
{
    // If in an Admin page.
    if ($this->isAdmin()) {
        $this->enable([
            'onGetPageBlueprints' => ['onGetPageBlueprints', 0],
            'onGetPageTemplates' => ['onGetPageTemplates', 0],
        ]);
    }
}

/**
 * Add blueprint directory.
 */
public function onGetPageBlueprints(Event $event): void
{
    $types = $event->types;
    $types->scanBlueprints('plugin://' . $this->name . '/blueprints');
}

/**
 * Add templates directory.
 */
public function onGetPageTemplates(Event $event): void
{
    $types = $event->types;
    $types->scanTemplates('plugin://' . $this->name . '/templates');
}

新しいページを作成

ブループリントとテンプレートファイルを定義した後、管理パネルで、 Add ボタンをクリックし、 “Mypage” を選択することで、新しいページを作成できます:

myPage.jpg

管理パネル編集フォームは、“New Text Field” という新しいカスタムフィールドを表示します:

myPage-customField.jpg