今回は WordPress のプラグインを使わずにカスタムフィールドで画像を登録する方法のご紹介です。
メディアを呼び出せるとリッチに画像をカスタムフィールドで登録できる機能を実装できます。
かみーゆ/フロントエンドエンジニア
T.D 様よりタイポの発見・ご指摘があり修正させていただきました!
ありがとうございました。
実例:商品登録などのカスタム投稿にスライドショーを追加するためにカスタムフィールドにメディアを追加
普通の投稿(ブログ記事以外)で投稿の種類を増やせるのが 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を使うか的な設定
)
);
}
フックのタイミングは以下を参考にすると良いです。
カスタム投稿の編集画面にメタボックスの追加
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 = array();
// 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 wp_nonce_field( 'my_action', 'my_nonce' ); ?>
<?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()
が無茶便利でした!
add_action( 'admin_enqueue_scripts', 'add_api' );
function add_api() {
wp_enqueue_media();
}
JavaScript API の調整
編集画面に JavaScript API を使って画像追加、削除ボタンから動的に画像を操作できるよう管理画面の footer 部分に JavaScript を追加します。
画像が選択されたら、JS で仕込んでおいた img タグを表示するように JavaScript を仕込んでおきます。これで UI(見た目)もそこそこきれい。
add_action( 'admin_footer', 'add_script' );
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
}
画像と画像名を保存
画像と画像名を保存できるようにします。
add_action( 'save_post', 'save_products' );
function save_products( $post_id ) {
if( isset( $_REQUEST['my_nonce'] )) {
if(!wp_verify_nonce($_POST['my_nonce'], 'my_action')) {
return;
}
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if(!current_user_can('edit_post', $post_id)) {
return;
}
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 を抑え軽くすることができる
- 余計な機能を減らすことでユーザーが迷わない
利用するのはお客さん。
ブログなのか、企業サイトなのかなどで何を強化するなどがまったく違ってきますのでニーズに合わせてカスタマイズするのがディベロッパーの使命かと思います^ ^。
まとめ
こんな感じで、画像がカスタム投稿でもリッチに登録できるようになりました!!
工夫したらカテゴリなどのサムネ登録などでも応用できます。
みなさんのコーディングライフの一助となれば幸いです。
最後までお読みいただきありがとうございました。
更新履歴
2021 年 1 月 13 日追記
サイトをリロードやプレビューへ切り替えた際にデータが消えるバグを発見し修正しました。
2022 年 12 月 17 日追記
セキュリティー対策のコードを追記しました。
メディアを保存するための JS の記載のある add_script
で不具合が見つかったため書き換えました。