アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

WordPress プラグインでエディタにボタンを追加する 3

WordPress プラグインでエディタにボタンを追加する方法の覚え書き。今回は画像の挿入などでおなじみのメディア ボタンを追加してみる。

2010/4/11 この記事で取り上げているショートコードの挿入処理は、編集モードがビジュアルの時に正しく動作しません。この問題の原因と対策は WordPress プラグインでエディタにボタンを追加する 4 へまとめたので、そちらをお読みください。

メディアボタンとは?

メディア ボタンは画像や音声ファイルのアップロードや挿入といった複雑なデータ操作を行うために用意されている。

メディア ボタン

単にボタンを追加するだけなら簡単だが、それだけではこの機能を選ぶ意味が薄い。そこで今回は画像のアップロードと挿入のようにダイアログ表示とエディタ連携を試してみる。

プラグイン実装

プラグインを実装する。MyPluginmyplugin となっている部分は自身のプラグイン名へ置き換えること。

<?php
/**
 * プラグインの処理を行います。
 */
class WpMyPlugin
{
    /** プラグインの配置されたディレクトリを示す URL。 */
    private $pluginDirUrl;

    /**
     * インスタンスを初期化します。
     */
    public function __construct()
    {
        $this->pluginDirUrl = WP_PLUGIN_URL . '/' . array_pop( explode( DIRECTORY_SEPARATOR, dirname( __FILE__ ) ) ) . "/";

        // ハンドラの登録
        if( is_admin() )
        {
            // アクション
            add_action( "admin_head_media_upload_myplugin_form", array( &$this, "onMediaHead"      )     );
            add_action( "media_buttons",                         array( &$this, "onMediaButtons"   ), 20 );
            add_action( "media_upload_myplugin",                 "media_upload_myplugin"                 );

            // フィルタ
            add_filter( "admin_footer", array( &$this, "onAddShortCode" ) );
        }
    }

    /**
     * ショートコードを挿入する為のスクリプトをページに埋め込みます。
     */
    public function onAddShortCode()
    {
        // 投稿の編集画面だけを対象とする
        if( strpos( $_SERVER[ "REQUEST_URI" ], "post.php"     ) ||
            strpos( $_SERVER[ "REQUEST_URI" ], "post-new.php" ) ||
            strpos( $_SERVER[ "REQUEST_URI" ], "page-new.php" ) ||
            strpos( $_SERVER[ "REQUEST_URI" ], "page.php"     ) )
        {
            echo <<<HTML
<script type="text/javascript">
//<![CDATA
function onMyPluginShortCode( value ) { edInsertContent( edCanvas, value ); }
//]]>
</script>
HTML;
        }
    }

    /**
     * メディアボタンを設定する時に発生します。
     */
    public function onMediaButtons()
    {
        global $post_ID, $temp_ID;

        $id     = (int)( 0 == $post_ID ? $temp_ID : $post_ID );
        $iframe = apply_filters( "media_upload_myplugin_iframe_src", "media-upload.php?post_id={$id}&amp;type=myplugin&amp;tab=myplugin" );
        $option = "&amp;TB_iframe=true&amp;keepThis=true&amp;height=500&amp;width=640";
        $title  = "WP-MyPlugin";
        $button = "{$this->pluginDirUrl}images/button.png";

        echo '<a href="' . $iframe . $option . '" class="thickbox" title="' . $title . '"><img src="' . $button . '" alt="' . $title . '" /></a>';
    }

    /**
     * メディアボタンから起動されたダイアログの内容を出力する為に発生します。
     */
    public function onMediaButtonPage()
    {
        echo <<<HTML
<form name="url_editor">
    テキスト : <input type="text" id="myplugin_data" size="30" />
    <p>
    <input type="button" class="button-primary" value="投稿に挿入" onclick="javascript:wpMyPlugin.onClickSubmitButton()" />
    </p>
</form>
HTML;
    }

    /**
     * メディアボタンから表示したウィンドウのヘッダが読み込まれる時に呼び出されます。
     */
    public function onMediaHead()
    {
        echo '<script type="text/javascript" src="' . $this->pluginDirUrl . 'js/editor.js"></script>';
    }

    /**
     * メディアボタンから表示したウィンドウのタブが設定される時に呼び出されます。
     *
     * @param	$tabs	規定のタブ情報コレクション。
     *
     * @return	実際に表示するタブ情報コレクション。
     */
    function onModifyMediaTab( $tabs )
    {
        return array( "myplugin" => "ショートコードの編集" );
    }
}

// プラグインのインスタンス生成
if( class_exists( WpMyPlugin ) )
{
    $wpMyPlugin = new WpMyPlugin();

    // 以下の関数は管理画面限定
    if( is_admin() )
    {
        /**
         * メディアボタンからダイアログが起動された時に呼び出されます。
         */
        function media_upload_myplugin()
        {
            wp_iframe( "media_upload_myplugin_form" );
        }

        /**
         * メディアボタンから起動されたダイアログの内容を出力する為に呼び出されます。
         */
        function media_upload_myplugin_form()
        {
            global $wpMyPlugin;

            add_filter( "media_upload_tabs", array( &$wpMyPlugin, "onModifyMediaTab" ) );

            echo "<div id=\"media-upload-header\">\n";
            media_upload_header();
            echo "</div>\n";

            $wpMyPlugin->onMediaButtonPage();
        }
    }
}

onAddShortCode はダイアログ側のスクリプトから呼び出されるスクリプトの埋め込みを行っている。実装の都合上、ダイアログ側から edInsertContent を呼び出せないため代替となる関数を埋め込んでいる。

onMediaButtons ではメディア ボタンを設定している。WordPress で記事の編集画面を開いて HTML を眺めるとわかるが標準の画像挿入などもこのようなリンク タグをページに埋め込むことで実現されているようだ。

ボタン用の画像を指定する場合、サイズは 16x16 ピクセルとなる。WP-ImaGeoMap ではフルカラーの透過 PNG を使用したが古いブラウザを考慮するならば透過 GIF にした方がよいかもしれない。

JavaScript

フォームに入力された内容を元に記事へショートコードを挿入するスクリプトは以下。

/**
 * プラグインのショートコード作成と挿入を行います。
 */
var WpMyPlugin = function() {
    var data = null;

    /**
     * ショートコードを取得します。
     *
     * @return	ショートコード。
     */
    function getShorCode() {
        return "[test]" + ( data == null ? "" : data.value ) + "[/test]";
    }

    /**
     * インスタンスを初期化します。
     */
    this.initialize = function() {
        data = document.getElementById( "myplugin_data" );
    };

    /**
     * 「投稿に挿入」ボタンが押された時に発生します。
     */
    this.onClickSubmitButton = function() {
        self.parent.onMyPluginShortCode( getShorCode() );
        self.parent.tb_remove();
    };
};

// 唯一の WpMyPlugin インスタンスを生成
var wpMyPlugin = new WpMyPlugin();

window.onload = function() {
    wpMyPlugin.initialize();
};

「投稿に挿入」ボタンが押された時に呼び出される onClickSubmitButton ではショートコード挿入してからダイアログを閉じている。ダイアログは子ウィンドウとして起動されているため、親となる編集画面のスクリプトを呼び出す場合は self.parent でアクセスする必要がある。

編集画面のエディタにテキスト挿入するために必要な edInsertContent へは直にアクセスできない。よっての編集画面のほうに埋め込まれたスクリプトの関数を呼び出す事で edInsertContent を間接実行している。

サンプル プログラム

今回の記事で実装したサンプル プログラムを公開。WP-MyPlugin という名前の WordPress プラグインとなる。これをプラグイン ディレクトリにアップロードして有効化すればメディア ボタンの動作を確認できる。

Comments from WordPress

  • zzrgtr zzrgtr 2010-04-09T11:10:26Z

    参考になる解説を有難うございます。

    1つ質問があります。サンプルプラグインを実行してみますと、エディタをHTMLモードにすると正常に動作しますが、ビジュアルモードですとショートコードが挿入されません。何が原因と考えられるでしょうか。

  • akabeko akabeko 2010-04-09T11:43:49Z

    ご指摘ありがとうございます。調べておきます。原因が判明したら、この記事を更新するか、新しい記事を書きたいと思います。

  • akabeko akabeko 2010-04-11T06:26:56Z

    新しい記事として、原因と対策を書きました。