JS で WordPress のビジュアルエディタに独自機能を追加する

こんにちは、元 WordPress エンジニアです。 かれこれ1年以上ぶりに WordPress を触っております。つらい。

ちょっと前まで個人でとあるメディアの改修を手伝っておりまして、もともとそのサイトは更新に際していくつかの問題を抱えていたのですが、その中で解決したもののひとつが結構有用なのでは、と思ったのでご紹介します。

今回やりたかったのは、「画像に付随する引用リンクをもっと簡単に追加できるようにしたい」というもの。 具体的には以下のようなコードをビジュアルエディタ上からボタンひとつでできるようにしてほしいという要望でした。

<p>出展:<a href=“トップレベルドメイン/hoge/hoge.html”>トップレベルドメイン</a><p>  

という感じです。 このサイトでは1つの画像を大量に記事内で利用している写真主体のメディアで画像の引用を多用していたのですが、毎回画像の下に href の中にはフルパス、内包するテキストには見た目の都合上トップレベルドメインのみを引っ張る必要がありました。 この作業が非常に面倒だったっぽい。 そこでボタンひとつで簡単に設置できるようにカスタマイズしてあげることに。

調べたところ WordPress のビジュアルエディタは WordPress のコアじゃなくて、TinyMCE とかいうウェブベースの WYSIWYG を利用してるらしくて、ビジュアルエディタに機能を追加するには TinyMCE 用のプラグインを作らないといけないらしい。 ただ、それがめちゃんこ簡単で、JS が雰囲気わかる人だったら誰でも作れる感じでした。

公式サイトに色々載っているので参照ください。

参照:http://www.tinymce.com/wiki.php/API3:method.tinymce.create

プラグインを作るぞ

ファイルの場所ですが、後から任意で引っ張れるのでテーマファイルの直下に admin_hogehoge みたいなフォルダを作って機能毎に分離する感じが良いと思います。

プラグインファイル

まずはプラグインファイルを作ります。

// editor_plugin.js

(function( $, document, window ){

    tinymce.create(

        'tinymce.plugins.MyButtons', {

            init: function( ed, url ) {

                ed.addButton(
                    'blockquote_link', {
                        title: '画像の引用リンク',
                        image: url + "/image/ico.png",
                        cmd: 'blockquote_cmd'
                    }
                );

                ed.addCommand( 'blockquote_cmd', function() {

                    ed.windowManager.open({

                        url: url + "/dialog.html",
                        width: 480,
                        height: 160,
                        title: '画像の参照元 URL を入力してください'

                    }, {
                        custom_param: 1
                    });

                });
            },

            createControl: function(n,cm) {

                return null;

            }
        }
    );
    tinymce.PluginManager.add(

        'custom_button_script',
        tinymce.plugins.MyButtons

    );
})(jQuery, document, window);

functions.php

次に作ったファイルの機能を引っ張るために functions.php に以下のような記述を行います。

/**
 * ボタンの追加
 */
function register_button($buttons) {  
    $buttons[] = 'blockquote_link';
    return $buttons;
}
add_filter('mce_buttons', 'register_button');

function mce_plugin($plugin_array) {  
    $plugin_array['custom_button_script'] = get_template_directory_uri() . '/admin-function/blockquote/editor_plugin.js';
    return $plugin_array;
}
add_filter('mce_external_plugins', 'mce_plugin');

場合によって HTML

ぼくの場合は windowManager.open を使ってダイアログ上から URL を入れられるようにしたかったので、そのための HTML も書いておきます。CSS は Bootstrap で。ドメインを取得するのと、プラグイン側に値を渡すスクリプトを jQuery でちょろっと書いています

<!— dialog.html —>  
<!DOCTYPE html>  
<html lang="ja">  
<head>  
    <meta charset="UTF-8">
    <title>画像の引用リンク</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
    <link href="../css/styles.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script>
        (function( $, window, document, _ ){

            var topDomain;

            function getDomain( i_data ) {

                var url = i_data;
                var arr_uri = url.match(/^(.*?:\/\/)(.*?)([a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})[\:[0-9]*]?([\/].*?)?$/i);

                topDomain = arr_uri[1] + arr_uri[3];
            }

            // submit 処理(プラグイン側に URL を渡す)
            $(document).on('click','#submit',function() {

                var url = _.escape($('#image_url').val());

                getDomain( url );

                var linkTag = '<p class="quote_link">出展:<a href="' + url + '" target="_blank">' + topDomain + '</a></p>';

                top.tinymce.activeEditor.selection.setContent(linkTag);
                top.tinymce.activeEditor.windowManager.close();

                return false;
            });

            // キャンセル処理
            $(document).on('click','#cancel',function(){

                $('#image_url').val('');
                top.tinymce.activeEditor.windowManager.close();

                return false;

            });

        })(jQuery, window, document, _);
    </script>
</head>  
<body>

    <div class="inner" style="padding: 30px;">
        <input type="text" id="image_url" class="form-control" style="margin-bottom: 20px;" placeholder="(例 http://hogehoge.com/hogehoge/hogehoge.jpg">

        <p style="text-align: center;">
            <input type="button" id="cancel" class="btn btn-danger" value="Cancel" onclick="return false;" style="margin-right: 10px;">
            <input type="button" class="btn btn-primary" id="submit" value="OK" onclick="return false;" /></p>
    </div>
</body>  
</html>

あとは、ボタンに当てるための画像(20x20くらい)を用意すれば OK です。 挙動はこんな感じ。

http://quick.as/rqbkcnayj

これで完成です!
他にもプラグイン入れたり色々やりようはありますが、調べた中だとこれが一番シンプルでやりやすい感じでした。 今回の例以外にも、色々ワイワイしたいときに一々プラグイン探したり、そのプラグインの動作検証するより早そう。
この機能も、色々調べながらやっても1時間もかかりませんでした。あと基本なんでもいけるっぽいのが強い。

久しぶりに触りましたがさすがおれたちの WordPress! 便利! 退っ引きならない事情で触ることがあったときにまた会おうな!