WP10は弊社が掲げる「WordPressを使った10倍速開発」です。
10倍とは、フルスクラッチに比べて10倍ということです。

この連載ではWP開発に長く携わっている弊社のWordPress開発ベストプラクティスを発信していきます。

第二回は「ACFでJavaScriptのフックを使って、ACFの繰り返しフィールドの内容をコピーする」です。ACFとはAdvanced Custom Fieldsで、入稿画面を自由度高くカスタマイズできるPluginです。ノンコーディングで表側を作成することができるので、WordPressの高速開発を掲げるWP10ではマストなPluginです。

ACFではacf/save_postやACFのフィールドキーを使用する独自のフックがあります。あまり知られていませんが、実はACFはJavaScriptにも独自のフックが用意されています(公式ドキュメント)。

今回はappendというフックの使用方法を説明します。appendは「新しいHTMLが追加されたときに作動する」フックです。

作るもの

本の著者を説明するリピーターフィールドを作成すると仮定します。リピーターフィールドの項目は「画像」「タイトル」「著者」にしています。

しかし、「夏目漱石」を2度入力するのは煩雑です。そんな時はappendのフックを使って入力を楽にしましょう!

目次へ戻る

仕様

  • 「行をコピー」のボタンを作成する
  • 「行をコピー」をクリックすると、著者名が入った状態で新しい行が作成される

では実際に作成してみましょう。

目次へ戻る

「行をコピー」ボタンを追加する

var $copyBtn = $('<li><a class="acf-button button button-primary copy" data-event="add-row">行をコピー</a></li>');
$('ul.acf-actions.acf-hl').append($copyBtn);

JavaScriptでコピーボタンを用意し、要素をDOMに追加します。すると、「行を追加」ボタンの左に「行をコピー」ボタンが表示されました!

目次へ戻る

「コピー」ボタンをクリックすると、著者名がコピーされる

// ACFのJSにフック
acf.add_action( 'append', function( $el2 ){

    // 「行をコピー」ボタンを押した時のみ、コピーされる
    if ( $el2.context.innerHTML !== '行をコピー' ) {
        return;
    }

    var tagInput            = 'input';

    // コピー元のフィールドを取得
    var $prevField       = $('div.acf-repeater tr:nth-last-of-type(3)');
    var $prevInputs      = $prevField.find(tagInput);

    // 追加されたフィールドを取得
    var $nextField       = $el2;
    var $nextInputs      = $nextField.find(tagInput);

    // 著者名をコピーする
    let $next = $($nextInputs.get(2));
    let $prev = $($prevInputs.get(2));
    $next.val( $prev.val() );
});

「行をコピー」をクリックすると、新しいリピーターフィールドのDOMが追加されます。ACFのappendフックが発火し、acf.add_actionで作成した関数が作動します。これにより、前の行に入力されている「著者」の文字列が新しい行にコピーされました。

コメント「著者名をコピーする」で$($prevInputs.get(1))とすると、「タイトル」に入力された文字列が新しい行にコピーされます。

目次へ戻る

(発展編1)画像をコピーする

// 「行をコピー」ボタンを押した時のみ、コピーされる
if ( $el2.context.innerHTML !== '行をコピー' ) {
    return;
}

var classAcfImgUploader = '.acf-image-uploader';

// 追加されたフィールドを取得
var $nextField       = $el2;
var $nextImgUploader = $nextField.find(classAcfImgUploader);

// コピー元のフィールドを取得
var $prevField       = $('div.acf-repeater tr:nth-last-of-type(3)');
var $prevImgUploader = $prevField.find(classAcfImgUploader);

// 画像をコピーする
let $next = $($nextImgUploader.get(0));
let $prev = $($prevImgUploader.get(0));

// 画像が挿入済みである時のクラスを付与
if( $prev.hasClass('has-value') ) {
    $next.addClass('has-value');
}

var $nextImg = $next.find('[data-name="image"]');
var $prevImg = $prev.find('[data-name="image"]').attr('src');
$nextImg.attr('src', $prevImg);
});

画像をコピーする場合は少し特殊です。

画像は「acf-image-uploader」というクラスが付与されています。このため、inputタグで入力した内容とは要素の取得の方法が異なります。上記のコードを実行した結果は下記のようになり、同じ画像を選択する手間を省くことができます。

目次へ戻る

(発展編2)全ての要素をコピーする(コードの全体像)

jQuery(function( $ ) {

    // 「行のコピー」追加
    var $copyBtn = $('<li><a class="acf-button button button-primary copy" data-event="add-row">行をコピー</a></li>');
    $('ul.acf-actions.acf-hl').append($copyBtn);

    // ACFのJSにフック
    acf.add_action( 'append', function( $el2 ){

        // 「行をコピー」ボタンを押した時のみ、コピーされる
        if ( $el2.context.innerHTML !== '行をコピー' ) {
            return;
        }

        var tagInput            = 'input';
        var classAcfImgUploader = '.acf-image-uploader';

        // 追加されたフィールドを取得
        var $nextField       = $el2;
        var $nextInputs      = $nextField.find(tagInput);
        var $nextImgUploader = $nextField.find(classAcfImgUploader);

        // コピー元のフィールドを取得
        var $prevField       = $('div.acf-repeater tr:nth-last-of-type(3)');
        var $prevInputs      = $prevField.find(tagInput);
        var $prevImgUploader = $prevField.find(classAcfImgUploader);

        // テキストやチェックボックスをコピーする
        for ( let i = 0, len = $prevInputs.length; i < len; ++i ){
            let $next = $($nextInputs.get(i));
            let $prev = $($prevInputs.get(i));
            $next.val( $prev.val() );
        }

        // 画像をコピーする
        var $next = $($nextImgUploader.get(0));
        var $prev = $($prevImgUploader.get(0));

        // 画像が挿入済みである時のクラスを付与
        if( $prev.hasClass('has-value') ) {
            $next.addClass('has-value');
        }

        var $nextImg = $next.find('[data-name="image"]');
        var $prevImg = $prev.find('[data-name="image"]').attr('src');
        $nextImg.attr('src', $prevImg);
    });
});

コードの全体像です。このコードを記述した状態で「行をコピー」ボタンをクリックすると、直前の行と全く同じ繰り返しフィールドが作成されます。

目次へ戻る

終わりに

いかがでしたでしょうか。ACFは他にも便利なJavaScriptのフックがあるので、ぜひ活用してみてください!

次回は「ユーザー一覧画面にカラムを追加する方法」をご紹介します!

この記事をシェアする:

WP10の連載一覧(全5件)

東日本橋の制作・開発会社 プレスマンのスタッフブログ