Как сделать таким способом 2+ метабокса?

Ссылка скопирована
1 ответ

Хочу создать несколько метабоксов с разной галереей внутри каждого.
ДА, Я ЗНАЮ ПРО 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х галерей

Если нужно больше таких окон, то тут уже нужно придумывать счетчик с перебором

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Мария Код Ответ

Чтобы сделать несколько метабоксов с галереями, нельзя использовать одни и те же 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',
    ]);
});

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>';
}

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);
    }
});

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 галерей без копирования всего кода.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно