Как сделать таким способом 2+ метабокса?
Хочу создать несколько метабоксов с разной галереей внутри каждого.
ДА, Я ЗНАЮ ПРО ACF, я хочу именно для себя научиться нативно-кодом-руками - я люблю докапываться как все устроено, но не без того, чтобы заходить в тупики. Я нашел вот такой способ создать метабокс с галереей, и когда я добавляю только один метабокс, все сохраняется, работает и выводится отлично и без проблем
function gallery_metabox_enqueue($hook) { if ( 'post.php' == $hook || 'post-new.php' == $hook ) { wp_enqueue_script('gallery-metabox', get_template_directory_uri() . '/js/gallery-metabox.js', array('jquery', 'jquery-ui-sortable')); wp_add_inline_style( 'gallery-metabox', '#gallery-metabox-list li {float: left; width: 30%; text-align: center; margin: 10px 10px 10px 0; cursor: move;}' ); } } add_action('admin_enqueue_scripts', 'gallery_metabox_enqueue'); function gallery_meta_save($post_id) { if (!isset($_POST['gallery_meta_nonce']) || !wp_verify_nonce($_POST['gallery_meta_nonce'], basename(__FILE__))) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (isset($_POST['gallery_images']) && is_array($_POST['gallery_images'])) { $images = array_map('sanitize_text_field', $_POST['gallery_images']); update_post_meta($post_id, 'gallery_images', $images); } } add_action('save_post', 'gallery_meta_save'); function gallery_meta_callback($post) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce'); $gallery_images = get_post_meta($post->ID, 'gallery_images', true); ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list"> <?php if ($gallery_images) : ?> <?php foreach ($gallery_images as $image_id) : ?> <li> <?php echo wp_get_attachment_image($image_id, 'thumbnail'); ?> <input type="hidden" name="gallery_images[]" value="<?php echo esc_attr($image_id); ?>"> <a class="remove-image" href="#">Remove image</a> </li> <?php endforeach; ?> <?php endif; ?> </ul> <a class="gallery-add button" href="#" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php } function add_gallery_metabox($post_type) { add_meta_box( 'gallery-metabox', 'Gallery', 'gallery_meta_callback', $post_type, 'normal', 'high' ); } add_action('add_meta_boxes', 'add_gallery_metabox'); |
function gallery_metabox_enqueue($hook) { if ( 'post.php' == $hook || 'post-new.php' == $hook ) { wp_enqueue_script('gallery-metabox', get_template_directory_uri() . '/js/gallery-metabox.js', array('jquery', 'jquery-ui-sortable')); wp_add_inline_style( 'gallery-metabox', '#gallery-metabox-list li {float: left; width: 30%; text-align: center; margin: 10px 10px 10px 0; cursor: move;}' ); } } add_action('admin_enqueue_scripts', 'gallery_metabox_enqueue'); function gallery_meta_save($post_id) { if (!isset($_POST['gallery_meta_nonce']) || !wp_verify_nonce($_POST['gallery_meta_nonce'], basename(__FILE__))) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (isset($_POST['gallery_images']) && is_array($_POST['gallery_images'])) { $images = array_map('sanitize_text_field', $_POST['gallery_images']); update_post_meta($post_id, 'gallery_images', $images); } } add_action('save_post', 'gallery_meta_save'); function gallery_meta_callback($post) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce'); $gallery_images = get_post_meta($post->ID, 'gallery_images', true); ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list"> <?php if ($gallery_images) : ?> <?php foreach ($gallery_images as $image_id) : ?> <li> <?php echo wp_get_attachment_image($image_id, 'thumbnail'); ?> <input type="hidden" name="gallery_images[]" value="<?php echo esc_attr($image_id); ?>"> <a class="remove-image" href="#">Remove image</a> </li> <?php endforeach; ?> <?php endif; ?> </ul> <a class="gallery-add button" href="#" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php } function add_gallery_metabox($post_type) { add_meta_box( 'gallery-metabox', 'Gallery', 'gallery_meta_callback', $post_type, 'normal', 'high' ); } add_action('add_meta_boxes', 'add_gallery_metabox');
JS-часть, файл gallery-metabox.js
jQuery(function($) { var file_frame; $(document).on('click', 'a.gallery-add', function(e) { e.preventDefault(); if (file_frame) { file_frame.open(); return; } file_frame = wp.media({ title: $(this).data('uploader-title'), button: { text: $(this).data('uploader-button-text'), }, multiple: true }); file_frame.on('select', function() { var list = $('#gallery-metabox-list'), selection = file_frame.state().get('selection'); selection.each(function(attachment) { attachment = attachment.toJSON(); list.append('<li><input type="hidden" name="gallery_images[]" value="' + attachment.id + '"><img class="image-preview" src="' + attachment.sizes.thumbnail.url + '"><a class="remove-image" href="#">Remove image</a></li>'); }); }); file_frame.open(); }); $(document).on('click', 'a.remove-image', function(e) { e.preventDefault(); $(this).parent().remove(); }); }); |
jQuery(function($) { var file_frame; $(document).on('click', 'a.gallery-add', function(e) { e.preventDefault(); if (file_frame) { file_frame.open(); return; } file_frame = wp.media({ title: $(this).data('uploader-title'), button: { text: $(this).data('uploader-button-text'), }, multiple: true }); file_frame.on('select', function() { var list = $('#gallery-metabox-list'), selection = file_frame.state().get('selection'); selection.each(function(attachment) { attachment = attachment.toJSON(); list.append('<li><input type="hidden" name="gallery_images[]" value="' + attachment.id + '"><img class="image-preview" src="' + attachment.sizes.thumbnail.url + '"><a class="remove-image" href="#">Remove image</a></li>'); }); }); file_frame.open(); }); $(document).on('click', 'a.remove-image', function(e) { e.preventDefault(); $(this).parent().remove(); }); });
Но когда пробую добавить еще один метабокс, то фотографии загружаются, но не сохраняются. Я писал GPT, оно мне сказало глянуть в логи, там "дата" картинок тогда не передается. Ничего не помогло, что оно мне советовало. Вот когда один метабокс - то все работает и выводится, а два и больше - уже нет. Так что это не "конфликт плагинов" - так бы не работал и один, и у меня очень мало плагинов. на метабоксы нету никакого, acf нету и близко.
Один из вариантов что пробовал, но пробовал разное, а код длинный. Покажите пожалуйста правильный пример с двумя метабоксами-галереями - пример с текстом не помог.
function add_gallery_metaboxes($post_type) { $types = array('post', 'product', 'custom-post-type'); if (in_array($post_type, $types)) { // Add the first metabox add_meta_box( 'gallery-metabox-first', // Unique identifier for the first metabox 'Gallery First', // Title of the first metabox 'gallery_meta_callback_first', // Callback function to display the first metabox content $post_type, 'normal', 'high', array('id' => 'first') // Pass a unique ID as an argument ); // Add the second metabox add_meta_box( 'gallery-metabox-second', // Unique identifier for the second metabox 'Gallery Second', // Title of the second metabox 'gallery_meta_callback_second', // Callback function to display the second metabox content $post_type, 'normal', 'high', array('id' => 'second') // Pass a unique ID as an argument ); } } add_action('add_meta_boxes', 'add_gallery_metaboxes'); function gallery_meta_callback_first($post, $metabox) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce_first'); $gallery_id = isset($metabox['args']['id']) ? $metabox['args']['id'] : 'first'; // Get the unique ID ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list-<?php echo $gallery_id; ?>" style="display:flex; flex-wrap:wrap;gap: 10px;"> <!-- Your code to display images and input fields for the first metabox here --> </ul> <a class="gallery-add button" href="#" data-gallery-id="<?php echo $gallery_id; ?>" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php } function gallery_meta_callback_second($post, $metabox) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce_second'); $gallery_id = isset($metabox['args']['id']) ? $metabox['args']['id'] : 'second'; // Get the unique ID ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list-<?php echo $gallery_id; ?>" style="display:flex; flex-wrap:wrap;gap: 10px;"> <!-- Your code to display images and input fields for the second metabox here --> </ul> <a class="gallery-add button" href="#" data-gallery-id="<?php echo $gallery_id; ?>" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php } |
function add_gallery_metaboxes($post_type) { $types = array('post', 'product', 'custom-post-type'); if (in_array($post_type, $types)) { // Add the first metabox add_meta_box( 'gallery-metabox-first', // Unique identifier for the first metabox 'Gallery First', // Title of the first metabox 'gallery_meta_callback_first', // Callback function to display the first metabox content $post_type, 'normal', 'high', array('id' => 'first') // Pass a unique ID as an argument ); // Add the second metabox add_meta_box( 'gallery-metabox-second', // Unique identifier for the second metabox 'Gallery Second', // Title of the second metabox 'gallery_meta_callback_second', // Callback function to display the second metabox content $post_type, 'normal', 'high', array('id' => 'second') // Pass a unique ID as an argument ); } } add_action('add_meta_boxes', 'add_gallery_metaboxes'); function gallery_meta_callback_first($post, $metabox) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce_first'); $gallery_id = isset($metabox['args']['id']) ? $metabox['args']['id'] : 'first'; // Get the unique ID ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list-<?php echo $gallery_id; ?>" style="display:flex; flex-wrap:wrap;gap: 10px;"> <!-- Your code to display images and input fields for the first metabox here --> </ul> <a class="gallery-add button" href="#" data-gallery-id="<?php echo $gallery_id; ?>" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php } function gallery_meta_callback_second($post, $metabox) { wp_nonce_field(basename(__FILE__), 'gallery_meta_nonce_second'); $gallery_id = isset($metabox['args']['id']) ? $metabox['args']['id'] : 'second'; // Get the unique ID ?> <table class="form-table"> <tr> <td> <ul id="gallery-metabox-list-<?php echo $gallery_id; ?>" style="display:flex; flex-wrap:wrap;gap: 10px;"> <!-- Your code to display images and input fields for the second metabox here --> </ul> <a class="gallery-add button" href="#" data-gallery-id="<?php echo $gallery_id; ?>" data-uploader-title="Add image(s) to gallery" data-uploader-button-text="Add image(s)">Add Images</a> </td> </tr> </table> <?php }
jQuery(function($) { function handleGalleryMetabox(gallery_id) { var file_frames = {}; $(document).on('click', 'a.gallery-add', function(e) { e.preventDefault(); if (!file_frames[gallery_id]) { file_frames[gallery_id] = wp.media({ title: $(this).data('uploader-title'), button: { text: $(this).data('uploader-button-text'), }, multiple: true }); file_frames[gallery_id].on('select', function() { var list = $('#gallery-metabox-list-' + gallery_id), listIndex = list.find('li').length, selection = file_frames[gallery_id].state().get('selection'); selection.each(function(attachment) { attachment = attachment.toJSON(); list.append('<li><input type="hidden" name="' + gallery_id + '[' + listIndex + ']" value="' + attachment.id + '"><img class="image-preview" src="' + attachment.sizes.thumbnail.url + '"><a class="change-image button button-small" href="#" data-uploader-title="Change image" data-uploader-button-text="Change image">Change image</a><br><small><a class="remove-image" href="#">Remove image</a></small></li>'); listIndex++; }); makeSortable(gallery_id); }); } file_frames[gallery_id].open(); }); function resetIndex(gallery_id) { $('#gallery-metabox-list-' + gallery_id + ' li').each(function(i) { $(this).find('input:hidden').attr('name', gallery_id + '[' + i + ']'); }); } function makeSortable(gallery_id) { $('#gallery-metabox-list-' + gallery_id).sortable({ opacity: 0.6, stop: function() { resetIndex(gallery_id); } }); } $(document).on('click', 'a.remove-image', function(e) { e.preventDefault(); var gallery_id = $(this).data('gallery-id'); // Get the gallery ID $(this).parents('li').animate({ opacity: 0 }, 200, function() { $(this).remove(); resetIndex(gallery_id); }); }); } // Handle the first gallery metabox handleGalleryMetabox('first'); // Handle the second gallery metabox handleGalleryMetabox('second'); }); |
jQuery(function($) { function handleGalleryMetabox(gallery_id) { var file_frames = {}; $(document).on('click', 'a.gallery-add', function(e) { e.preventDefault(); if (!file_frames[gallery_id]) { file_frames[gallery_id] = wp.media({ title: $(this).data('uploader-title'), button: { text: $(this).data('uploader-button-text'), }, multiple: true }); file_frames[gallery_id].on('select', function() { var list = $('#gallery-metabox-list-' + gallery_id), listIndex = list.find('li').length, selection = file_frames[gallery_id].state().get('selection'); selection.each(function(attachment) { attachment = attachment.toJSON(); list.append('<li><input type="hidden" name="' + gallery_id + '[' + listIndex + ']" value="' + attachment.id + '"><img class="image-preview" src="' + attachment.sizes.thumbnail.url + '"><a class="change-image button button-small" href="#" data-uploader-title="Change image" data-uploader-button-text="Change image">Change image</a><br><small><a class="remove-image" href="#">Remove image</a></small></li>'); listIndex++; }); makeSortable(gallery_id); }); } file_frames[gallery_id].open(); }); function resetIndex(gallery_id) { $('#gallery-metabox-list-' + gallery_id + ' li').each(function(i) { $(this).find('input:hidden').attr('name', gallery_id + '[' + i + ']'); }); } function makeSortable(gallery_id) { $('#gallery-metabox-list-' + gallery_id).sortable({ opacity: 0.6, stop: function() { resetIndex(gallery_id); } }); } $(document).on('click', 'a.remove-image', function(e) { e.preventDefault(); var gallery_id = $(this).data('gallery-id'); // Get the gallery ID $(this).parents('li').animate({ opacity: 0 }, 200, function() { $(this).remove(); resetIndex(gallery_id); }); }); } // Handle the first gallery metabox handleGalleryMetabox('first'); // Handle the second gallery metabox handleGalleryMetabox('second'); });
Дополнительно:
зачем Вам куча метабоксов?
Оформляйте все одним мета: разметку оформляйте через foreach (проверяйте одну опцию в базе, в которой будет лежать массив данных), легче будет добавлять функционал (сегодня у вас 2 фото, завтра 3. Снова кучу строк писать будете?) Пост данные при сейве проверяйте и формируйте массив данных, затем массив и сохраняйте в базу. Если будут какие-то дефолтные опции, используйте wp_parse_args...
з.ы. извините в Вашей простыне копаться лень
Ответы:
Наводка
function gallery_meta_save($post_id) { if (!isset($_POST['gallery_meta_nonce']) || !wp_verify_nonce($_POST['gallery_meta_nonce'], basename(__FILE__))) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (isset($_POST['gallery_images']) && is_array($_POST['gallery_images'])) { $images = array_map('sanitize_text_field', $_POST['gallery_images']); update_post_meta($post_id, 'gallery_images', $images); } if (isset($_POST['gallery_images_2']) && is_array($_POST['gallery_images_2'])) { $images_2 = array_map('sanitize_text_field', $_POST['gallery_images_']); update_post_meta($post_id, 'gallery_images_2', $images_2); } } |
function gallery_meta_save($post_id) { if (!isset($_POST['gallery_meta_nonce']) || !wp_verify_nonce($_POST['gallery_meta_nonce'], basename(__FILE__))) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (isset($_POST['gallery_images']) && is_array($_POST['gallery_images'])) { $images = array_map('sanitize_text_field', $_POST['gallery_images']); update_post_meta($post_id, 'gallery_images', $images); } if (isset($_POST['gallery_images_2']) && is_array($_POST['gallery_images_2'])) { $images_2 = array_map('sanitize_text_field', $_POST['gallery_images_']); update_post_meta($post_id, 'gallery_images_2', $images_2); } }
Соответственно, продублировать функцию gallery_meta_callback() с постфиксом _2
js не смотрел
Данный метод подойдет только для 2х галерей
Если нужно больше таких окон, то тут уже нужно придумывать счетчик с перебором
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Чтобы сделать несколько метабоксов с галереями, нельзя использовать одни и те же id, nonce, имена input и JS-селекторы для всех блоков. Один метабокс работает, потому что все данные пишутся в одно meta-поле. Для двух и более галерей нужно параметризовать код: у каждой галереи свой meta_key и свой контейнер.
Например, регистрируете метабоксы так:
add_action('add_meta_boxes', function () { add_meta_box('gallery_one', 'Галерея 1', 'render_gallery_metabox', 'post', 'normal', 'default', [ 'meta_key' => '_gallery_one', ]); add_meta_box('gallery_two', 'Галерея 2', 'render_gallery_metabox', 'post', 'normal', 'default', [ 'meta_key' => '_gallery_two', ]); });
В render-функции берёте
meta_keyиз аргументов:function render_gallery_metabox($post, $box) { $meta_key = $box['args']['meta_key']; $ids = get_post_meta($post->ID, $meta_key, true); $ids = is_array($ids) ? $ids : []; wp_nonce_field('save_gallery_metabox', 'gallery_metabox_nonce'); echo '<div class="gallery-metabox" data-field="' . esc_attr($meta_key) . '">'; echo '<input type="hidden" name="' . esc_attr($meta_key) . '" value="' . esc_attr(implode(',', $ids)) . '">'; echo '<button type="button" class="button gallery-add">Добавить изображения</button>'; echo '<ul class="gallery-list"></ul>'; echo '</div>'; }
Сохранение тоже должно проходить по списку ключей:
add_action('save_post', function ($post_id) { if (!isset($_POST['gallery_metabox_nonce']) || !wp_verify_nonce($_POST['gallery_metabox_nonce'], 'save_gallery_metabox')) { return; } foreach (['_gallery_one', '_gallery_two'] as $key) { $raw = sanitize_text_field($_POST[$key] ?? ''); $ids = array_filter(array_map('absint', explode(',', $raw))); update_post_meta($post_id, $key, $ids); } });
В JS ищите элементы относительно текущего метабокса, а не глобально:
const box = button.closest('.gallery-metabox'); const input = box.querySelector('input[type="hidden"]'); const list = box.querySelector('.gallery-list');const box = button.closest('.gallery-metabox'); const input = box.querySelector('input[type="hidden"]'); const list = box.querySelector('.gallery-list');
Для каждой галереи лучше хранить массив ID вложений, а не URL. URL может поменяться при переносе сайта, смене размера изображения или CDN, а ID остаётся нормальной связью с медиатекой. На фронте потом можно вывести нужный размер через
wp_get_attachment_image(), получить alt, title и srcset.Ещё одна типичная ошибка — один общий nonce на все галереи не проблема, но одно общее имя input уже проблема. Если у двух метабоксов поле называется одинаково, при сохранении последнее значение перезапишет первое. Поэтому ключи
_gallery_one,_gallery_twoи имена input должны быть разными.Причина тупика обычно одна: одинаковые id и глобальные селекторы. Сделайте метабокс переиспользуемым, а различия передавайте через
meta_key. Тогда можно создать 2, 5 или 10 галерей без копирования всего кода.