Joomla! の Plugin を自作する(4)OGPプラグイン(1)

Joomla! の Plugin を自作する(3)デフォルトの静的データをメタタグに挿入する の続きです。

なかなかはかどらないですね(笑)。

前回の最後に、「onContentBeforeDisplay では記事表示以外はイベントが発生しない?」と書いたのですが、考えてみれば当たり前で、記事を書き出す前のイベントですから、たとえば「すべてのカテゴリ一覧」のように記事を呼び出さないページ(アイテム?)ではこのイベントは発生しません。コンポーネントを呼び出すページも発生しませんね。

それに、カテゴリブログやカテゴリ一覧など記事を複数表示するページではプラグインが複数回呼ばれてしまいます。これはまずいですね。



どのグループの plugin でも全てのイベントが使えるようだ

現在進めている plugin は group="content"class plgContentImzOpenGraph ですので、Content に分類されたイベントしか使えないのかと思いましたら、そうではなく、System に分類されたイベントも発生するようです。たとえば、他は何も変えずに次のように試してみますと、設定したパラメータがオブジェクトとして素のまま表示されます。

public function onAfterRender()
{
    var_dump($this->params);
    // Do something onAfterRender
}

ただ、今度はページが管理であれフロントであれすべての場合に呼び出されることになります。


Open Graph プラグインの考え方

再度考え方を整理します。まず、やりたいことは、

  • <head> タグに type に合わせて prefix を追加する
  • ページの内容を判断して、つまり記事かカテゴリ一覧か、サードパーティのコンポーネントかなどを判断してメタタグを追加する
  • もちろん管理ページなど必要ないページは排除する


で、これまででわかったことを整理しますと、

  • plugin はグループに関係なくどのイベントも呼び出せる
  • Content グループのイベントは記事以外では呼び出されないし、表示記事の回数呼び出される


ということで、system プラグインでいくこととし、

  • まず、コンポーネントの種類とビュー形式を取得する
  • シングル記事、注目記事、カテゴリブロク、カテゴリ一覧、他のコンポーネントなどに振り分ける
  • 最適化した ogプロパティを設定する
  • og:type に応じた prefix を <head> タグに追加する


コンポーネントの種類とビュー形式を取得する

Content グループのイベントでは、パラメータが com_content.article 等のデータをもっていましたが、System グループのイベントはパラメータを持っていませんので自力で取得しなければなりません。


$app  = JFactory::getApplication();
$option = $app->input->get('option', '');
$view   = $app->input->get('view', '');
$scope  = $option . '.' . $view;

これで、$scopecom_content.article などの値を持ち、サードパーティのコンポーネントも、たとえば K2のアイテムは com_k2.item となります。これで記事内容で振り分けることが出来ます。


メタタグを <head> に挿入する

いろいろ試したところ、System グループのうち、<head> の中を操作できるイベントは次の3つに限られているようです。

  • onAfterDispatch
  • onBeforeRender
  • onBeforeCompileHead

とりあえず、onBeforeRender を使ってみます。

class plgSystemImzOpenGraph extends JPlugin {

    protected $autoloadLanguage = true;
    
    private $type;
    
    public function onBeforeRender() {

        $app  = JFactory::getApplication();
        $doc  = JFactory::getDocument();

        if($app->isAdmin()) {
            return;
        }

        $option = $app->input->get('option', '');
        $view   = $app->input->get('view', '');
        $scope  = $option . '.' . $view;
    
        // $scope で分岐
        // 以下チェック用
        $this->type = $this->params->get('imzopengraphtype');

        $doc->addCustomTag('<meta property="og:title" content="' . $this->params->get('imzopengraphtitle') . '"/>');
        $doc->addCustomTag('<meta property="og:type" content="' . $this->params->get('imzopengraphtype') . '"/>');
        $doc->addCustomTag('<meta property="og:image" content="' . JURI::base(false) . $this->params->get('imzopengraphimage') . '"/>');
        $doc->addCustomTag('<meta property="og:url" content="' . $this->params->get('imzopengraphurl') . '"/>');
        $doc->addCustomTag('<meta property="og:description" content="' . $this->params->get('imzopengraphdesc') . '"/>');
        $doc->addCustomTag('<meta property="og:site_name" content="' . $this->params->get('imzopengraphsitename') . '"/>');

    }
}


<head> に prefix を追加する

<head> タグを操作するには JResponse クラスを使うのがよさそうなんですが、今度は上にあげた3つのイベントではまだ値を持っておらず、onAfterRender を使うことになります。


上の続きです。

 public function onAfterRender() {
        
        $buf = JResponse::getBody();

        $ogPrefix = 'og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# ' . $this->type . ': http://ogp.me/ns/' . $this->type . '#';

        if(strpos($buf, '<head>') !== false) {
           $buf = preg_replace('/<head>/', '<head prefix="' . $ogPrefix . '">', $buf, 1);
       } else {
           $buf = preg_replace('/<head /', '<head prefix="' . $ogPrefix . '" ', $buf, 1);
      }

      JResponse::setBody($buf);

  }


これでなんとか骨格は出来たのではないかと思います。