Contents Management System

WordPress プラグインなしでカスタム投稿のカスタムフィールドにメディアを追加する方法

WordPress

フロントエンドエンジニアのかみーゆです。みなさん、WordPressはお好きですか?

今回はプラグインを使わずにカスタムフィールドで画像を登録する方法のご紹介です。

投稿画面から便利にかんたんに複数の画像登録したくて探していたらJavaScript APIが使えることを知りました。

メディアを呼び出せるとリッチに画像をカスタムフィールドで登録できる機能を実装できます。

この記事を書いた人

かみーゆ/フロントエンドエンジニア

セブ島在住の気ままな海外ノマドエンジニア。IT業界10年。テクニカルディレクター・エンジニア講師・ブリッジSEを経て今に至る。CMS concrete5エバンジェリスト。テックブログ以外も「磨耗しない人生の選択」や「海外生活」のライフスタイルについて発信。好きなものは肉とビール。

Read More

実例:商品登録などのカスタム投稿にスライドショーを追加するためにカスタムフィールドにメディアを追加

普通の投稿(ブログ記事以外)で投稿の種類を増やせるのがWordPressの便利なところですよね?
今回はお仕事で商品という種類の投稿を作って、いくつか画像を登録して投稿ごとに商品のスライドショーを実装しなければなりませんでした。

プラグイン・カスタムフィールドアドバンスを利用すればカンタンなんでしょうけど「テーマをインストールした瞬間から設定なしで使える」状態を目指したかったので、カスタマイズすることになりました。

商品登録などのカスタム投稿にスライドショーを追加

私が実際実装した内容に限りなく近い状態での実装方法をご紹介します。

カスタム投稿を新規で作成

function.phpなどにcreate_post_typeという関数を作って、新たにカスタム投稿を追加します。

add_action()は特定のアクションに対して指定した関数をフックさせる関数です。

この場合(initなので)プラグインなどの初期化のタイミングに実行されます。

今回はあくまで「カスタムフィールドにメディア(画像登録)を追加する方法」のご紹介なので、詳しい説明は割愛します。

add_action( 'init', 'create_post_type' );

function create_post_type() {
    $supports = array(
        'title',
        'editor',
        'author',
        'revisions',
    );

    register_post_type(
        'products', // カスタム投稿名
        array(
            'label' => '商品', // 管理画面の左メニューに表示されるテキスト
            'public' => true,
            'show_ui' => true,
            'show_in_menu' => true,
            'capability_type' => 'post',
            'rewrite' => true,
            'query_var' => false,
            'exclude_from_search' => false,
            'show_in_rest' => true,
            'rest_base' => 'products',
            'has_archive' => true, // アーカイブを有効にするか否か
            'menu_position' => 5, // 管理画面上でどこに配置するか今回の場合は「投稿」の下に配置
            'supports' => $supports // 投稿画面でどのmoduleを使うか的な設定
        )
    );
}

フックのタイミングは以下を参考にすると良いです。

プラグイン API/アクションフック一覧

カスタム投稿の編集画面にメタボックスの追加

add_meta_box()関数を使って登録エリアを作ります。

引数はこちらを参考にしてください。

関数リファレンス/add meta box

add_action( 'admin_menu', 'add_custom_fields' );

function add_custom_fields() {
    add_meta_box(
        'product_sectionid', //id(必須)
        '商品画像の登録',//title(必須)
        'product_custom_fields',//コールバック(必須)
        'products'//投稿の種類(必須、post、pageなど)
        'advanced',// 編集画面セクションが表示される部分(オプション)
        'default',//優先順位
    );
}

product_custom_fields関数内に実際登録させる内容コードを書きます。
以下のような感じで出力されるようにします。

カスタム投稿の編集画面にメタボックスの追加

今回は画像名と画像を3つまで登録できるようにしてみます。

実際のデータはフォームタグをhiddenで仕込んでおき、JSで動的に値を格納できるようにしておきます。

function product_custom_fields() {
    $product_image_name = array();
    $product_image = arra();

    // 3画像の格納
    for ( $i=0; $i < 3; $i++ ) {
        $product_image_name[] = get_post_meta( $post->ID, 'product-image-name_'.$i, true );
        $product_image[] = get_post_meta( $post->ID, 'product-image_'.$i, true );
    }    //登録画面に出力
?>
    <table class="form-table">
        <?php for ( $i=0; $i < 3; $i++ ):?>
            <tr class="form-field">
                <th scope="row">画像名<?php echo $i+ 1?></th>
                <td><input type="text" name="product-image-name_<?php echo $i?>" value="<?php echo esc_html($product_image_name[$i] ? $product_image_name[$i] : '')?>"></td>
            </tr>
            <tr class="form-field">
                <th scope="row">商品</th>
                <td>
                    <input type="hidden" id="product-image_<?php echo $i; ?>" name="product-image_<?php echo $i; ?>" value="<?php echo $product_image[$i] ? $product_image[$i] : '' ?>">
                    <div id="image-wrapper_<?php echo $i?>">
                    <?php if ( $product_image[$i] ) {
                        $product_thumb = wp_get_attachment_image_src ( $product_image[$i], 'thumbnail' );
                        ?>
                        <img src="<?php echo $product_thumb[0] ?>" width="<?php echo $product_thumb[1]; ?>" height="<?php echo $product_thumb[2]; ?>" class="custom_media_image">
                    <?php } ?>
                    </div>
                    <p><input type="button" class="button button-secondary media_button" name="media_button" value="追加" id="media-button_<?php echo $i?>" />
                    <input type="button" class="button button-secondary media_remove" name="media_remove" value="削除" id="media-remove_<?php echo $i?>"/></p>
                </td>
            </tr>
        <?php endfor;?>
    </table>
<?php
}

JavaScript APIの呼び出し

管理画面でメディアのJavaScript APIを利用してメディアのポップアップを呼び出せるようにします。

wp_enqueue_media()が無茶便利でした!

関数リファレンス/wp enqueue media

add_action( 'admin_enqueue_scripts', add_api );

function add_api() {
    wp_enqueue_media();
}

JavaScript APIの調整

編集画面にJavaScript APIを使って画像追加、削除ボタンから動的に画像を操作できるよう管理画面のfooter部分にJavaScriptを追加します。

画像が選択されたら、JSで仕込んでおいたimgタグを表示するようにJavaScriptを仕込んでおきます。これでUI(見た目)もそこそこきれい。

JavaScript APIの調整

add_action( 'admin_footer', array ( $this, 'add_script' ) );

public function add_script() {
?>
<script>
    jQuery(document).ready(
        function($) {
            let _custom_media = true,
            _orig_send_attachment = wp.media.editor.send.attachment;

            // 画像の登録
            $( '.media_button' ).each(function(index) {
                $(this).on("click", function(){
                    let send_attachment_bkp = wp.media.editor.send.attachment;
                    wp.media.editor.send.attachment = function(props, attachment){
                        if ( _custom_media ) {
                            $('#product-image_'+index).val(attachment.id);
                            $('#image-wrapper_'+index).html('<img class="custom_media_image" src="' + attachment.sizes.thumbnail.url + '" height="' + attachment.sizes.thumbnail.height + '" width="' + attachment.sizes.thumbnail.width + '">');
                        } else {
                            return _orig_send_attachment.apply( $(this).id, [props, attachment] );
                        }
                    }
                    wp.media.editor.open($(this));
                    return false;
                });
            });

            // 削除
            $( '.media_remove').each(function(index) {
                $(this).on("click", function(){
                    $('#product-image_'+index).val('');
                    $('#image-wrapper_' + index + ' .custom_media_image').remove();
                });
            });
        });
    </script>
<?php }
}

画像と画像名を保存

画像と画像名を保存できるようにします。

2021年1月13日追記

サイトをリロードやプレビューへ切り替えた際にデータが消えるバグを発見しました。

add_action( 'save_post', 'save_products' );

function save_products( $post_id ) {
    // 画像
    for ( $i=0; $i < 3; $i++ ) {
        if ( isset( $_POST['product-image-name_'.$i] ) ){
			if ( $_POST['product-image-name_'.$i] !== '' ){
				update_post_meta( $post_id, 'product-image-name_'.$i, $_POST['product-image-name_'.$i] );
			} else {
				delete_post_meta($post_id, 'product-image-name_'.$i);
			}
        }
        // 画像の保存
        if( isset( $_POST['product-image_' . $i] ) ) {
			if( $_POST['product-image_' . $i] !== '' ) {
				update_post_meta( $post_id, 'product-image_' . $i, $_POST['product-image_' . $i] );
			} else {
				delete_post_meta( $post_id, 'product-image_'.$i );
				}
        }
    }
}

プラグインなしで実装するメリット

ぶっちゃけWordPressってプラグインの方が安定してますしすべての機能を網羅していて痒いところに手が届きます。しかも無料です。

しかし「すべての機能」を網羅しているがゆえに不要な機能もたくさん付いています

私のカスタマイズするメリットは以下のような感じです。

  • サイトの軽量化プラグインを減らして不要なJSやCSSを抑え軽くすることができる
  • 余計な機能を減らすことでユーザーが迷わない

利用するのはお客さん。

ブログなのか、企業サイトなのかなどで何を強化するなどがまったく違ってきますのでニーズに合わせてカスタマイズするのがディベロッパーの使命かと思います^ ^。

まとめ

こんな感じで、画像がカスタム投稿でもリッチに登録できるようになりました!!

工夫したらカテゴリーなどのサムネ登録などでも応用できます。

みなさんのコーディングライフの一助となれば幸いです。

最後までお読みいただきありがとうございました。

「銀ねこアトリエ」のブログを定期購読しよう

Feedlyに登録する