【WordPress】オリジナルのクイックタグを作成する

WordPressのテキストエディタで使えるオリジナルクイックタグを作成していきます。クイックタグを使いこなせれば、タグやショートコードの入力の負担が相当減るので、ぜひ、覚えておきたいところです。

この記事では、テキストエディタのクイックタグについて書いています。従って、テキストエディタを使用するためのプラグイン「Classic Editor」の使用が前提となります。

クイックタグの使い方はクイックタグAPIに任せ、この記事では実例とコードの簡単な説明を残しておきます。また、JavaScriptについての解説はしていませんのでご了承ください。

環境
PHP
7.4
WordPress
5.9.1
Classic Editor
1.6.2

デフォルトのクイックタグを選別する

個人的に使用しないクイックタグを邪魔に感じるので、使うタグだけを残します。

functions.php
add_filter( 'quicktags_settings' , function ($qtInit) {
    // $qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,dfw'
    $qtInit['buttons'] = 'link';
    return $qtInit;
} , 10 , 1);

オリジナルのクイックタグを作る

まずは最も簡単なクイックタグを追加してみます。

実際の挙動

少ない文字数ではあまり恩恵を感じられませんが、引数が多いショートコードや、よく使うHTMLタグを登録しておけば、文字入力の負担がかなり減ります。

コード

functions.php
<?php
add_action('admin_print_footer_scripts', function () {
    // quicktagsが登録されていないページではクイックタグの追加をしない
    if ( !wp_script_is( 'quicktags' ) ) {
        return;
    }
?>
    <script type="text/javascript">
        // QTags.addButton(id, ボタンの文字, 開始タグ, 終了タグ);
        QTags.addButton('heading-2', 'h2', '<h2>', '</h2>');
    </script>
<?php
});

入力値で結果が変わるクイックタグを作る

次は入力値によって出力結果が変わるものを作ります。

実際の挙動

コード

これ以降、functions.phpPHP部分を省略し、JavaScript部分のみを抜粋して載せています

// QTags.addButton(id, ボタンの文字, コールバック関数);
QTags.addButton('unordered_list', 'ul', unordered_list);
function unordered_list(e, c, ed)
{
    const num = prompt('リストの数');

    if (num === '' || num === null) {
        return false;
    }

    QTags.insertContent(
        '<ul>\n' +
        '    <li></li>\n'.repeat(num) +
        '</ul>'
    );

    return false;
}

エディタで文字選択中と未選択で挙動を変える

エディタの文字選択状態で挙動を変えます。

実際の挙動

コード

// QTags.addButton(id, ボタンの文字, コールバック);
QTags.addButton('heading', 'heading', heading);
function heading(e, c, ed)
{
    const level = prompt('見出しレベル');

    if (level === '' || level === null) {
        return false;
    }

    // テキストエディタで文字選択中
    if (ed.canvas.selectionStart !== ed.canvas.selectionEnd) {
        this.tagStart = `<h${level}>`;
        this.tagEnd   = `</h${level}>`;
        QTags.TagButton.prototype.callback.call(this, e, c, ed);
    // 文字未選択
    } else {
        QTags.insertContent(
            `<h${level}></h${level}>`
        );
    }

    // console.log(ed.canvas); ブラウザ開発者ツールで確認
    return false;
}

インラインフレームを使ってショートコード入力を簡潔化する

最後に、非常に面倒なショートコードの引数入力を簡単にするクイックタグを作ります。最初の方法でも可能ですが、インラインフレームを使った方法がより簡単にショートコードを生成できます。

実際の挙動

WordPressに元々組み込まれているjQueryプラグインThickBoxを使用します。

コード

今までと違って少し複雑になります。

theme_dir/
|-- cli_view_url.php
|-- web_view_url.php
|-- ...
`-- functions.php
functions.php
<?php
/**
 * フック名はQTags.addButtonのコールバック関数内で実行する、tb_show()第二引数で指定のURL(type=<name>)を使う
 * media_upload_<type=name> となる。
 */
add_action('media_upload_code', function () {
    // 無名関数でも機能するがタブにスタイルシートが適応されない。media_**とする必要がある。
    wp_iframe('media_iframe_code');
});

function media_iframe_code()
{
    add_filter('media_upload_tabs', function ($tabs) {
        // 'tb_show(URLのtab=**)' => インラインフレームでのタブ表示名
        $tab_map = [
            'web_view_url' => 'web_tab',
            'cli_view_url' => 'cli_tab'
        ];

        return $tab_map;
    });

    media_upload_header();

    $current_view_url = filter_input(INPUT_GET, 'tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
    require_once __DIR__ . "/${current_view_url}.php";
}

add_action('admin_print_footer_scripts', function () {
    if ( !wp_script_is( 'quicktags' ) ) {
        return;
    }
?>
    <script type="text/javascript">
        QTags.addButton('quicktag_code', 'code', quicktag_code);
        function quicktag_code(e, c, ed)
        {
            tb_show('code', 'media-upload.php?type=code&tab=web_view_url&TB_iframe=true&keepThis=true');

            if (ed.canvas.selectionStart !== ed.canvas.selectionEnd) {
                send_to_editor = function (data) {
                    this.tagStart = data.s;
                    this.tagEnd   = data.e;
                    QTags.TagButton.prototype.callback.call(this, e, c, ed);
                };
            } else {
                send_to_editor = function (data) {
                    QTags.insertContent(data.s + data.e);
                };
            }

            return false;
        }
    </script>
<?php
});
web_view_url.php
// HTML(form)省略

<button id="insert" class="button button-primary" type="button" name="submit">Insert</button>
<button id="cancel" class="button" type="reset" name="submit">Cancel</button>

<script type="text/javascript">
(function($){
    'use strict';

    // HTML(form)処理省略

    $('#cancel').on('click', function(e) {
        if (confirm('cancel ?')) top.tb_remove();
    });

    $('#insert').on('click', function() {
        const lang = $('#lang').val();
        const label = $('#label').val();

        top.send_to_editor({
            s: `[code lang="${lang}" label="${label}"]\n`,
            e: '\n[/code]'
        });

        top.tb_remove();
    });
})(jQuery);
</script>
cli_view_url.php
<p style="margin: 1rem;">タブの切り替え</p>

今回はiframeでタブを使用しましたが、タブを使わない場合はadd_filter('media_upload_tabs')などのタブ関連コードは必要ありません。

おわりに

以上で、一通りのクイックタグを作成できるようになりました。
ただ、参考サイト様や海外ブログなどを拝見すると、この記事では使用していないコードなども出てきているので、もっと効率的な書き方ができたり、使える関数などがあるのかもしれません。WordPress本体のソースコードまでたどれば分かるかと思いますが、ひとまず自分が欲しい機能の実装はできたので良しとします。