Настраиваемый виджет выбора нескольких изображений

Вопрос или проблема

Я создал настраиваемый карусельный слайдер Swiper в качестве шаблонной части кастомной темы. Я хочу превратить этот компонент темы в виджет, чтобы иметь больше контроля над отображаемым содержимым. Он используется как горизонтальный слайдер логотипов, и на данный момент будет использовать один пост с галереей внутри для отображения логотипов брендов. Как мне создать модальное окно для виджета, который я пишу, чтобы открыть медиатеку WP и выбрать несколько изображений для использования в качестве изображений для слайдера? Это возможно?
Вот актуальный код:

<?php
$args = array(
'post_type' => 'post',
'name' => 'логотипы брендов'
);
$logo_img = new WP_Query( $args );
?>
<div class="row" style="margin-top:1em;margin-bottom:1em;">
<?php if( $logo_img->have_posts() ): while( $logo_img->have_posts() ): $logo_img->the_post();
$logo_gallery = get_post_gallery_images( $post->ID );
if( $logo_gallery ): ?>
<div class="swiper-container logo-slider" id="clients-logo-slider">
  <div class="swiper-wrapper" id="client-logo-wrapper">
<?php  foreach($logo_gallery as $logo ): ?>
    <img class="swiper-slide" src="https://wordpress.stackexchange.com/questions/355953/<?php echo $logo; ?>" alt="" width="100" id="client-logo"/>
<?php endforeach; ?>
<?php endif; ?>
  </div>
  <div class="swiper-scrollbar"></div>
</div>
<?php endwhile; ?>
<?php endif; wp_reset_postdata(); ?>
</div>

<script type="text/javascript">
(function($){
  $(document).ready(function(){
    var swiperLogos = new Swiper('.logo-slider',{
      autoplay: {
      delay: 5000,
      },
      slidesPerView: 'auto',
      slidesPerColumnFill: 'row',
      scrollbar: {
        el: '.swiper-scrollbar',
        draggable: true,
      },
    });
  });
}(jQuery));
</script>

Я помещу это внутри класса, чтобы создать функциональный виджет для использования в теме вместо шаблонной части. Вот код, который я пишу, чтобы обернуть существующий. Я заметил, что не могу выбрать несколько изображений.
Примечание: код еще не завершен. Я умею писать виджет, но сначала мне нужно решить проблему с выбором нескольких изображений.

class FeaturedLogoSlider extends WP_Widget {


  public function __construct()
  {
    parent::__construct(
      'featured-brands',
      'Слайдер логотипов брендов',
      array(
        'description' => __('Слайдер логотипов популярных брендов', '')
      )
    );
    add_action( 'widgets_init', array($this, 'initSidebar') );
    add_action( 'wp_enqueue_scripts', array($this, 'initScripts') );
  }

  public function initScripts()
  {
    wp_enqueue_script( 'media-upload' );
    wp_enqueue_media();
    wp_enqueue_script( 'medialib-script', plugins_url( 'medialib-script.min.js' ,__FILE__), array('jquery'), null );
    // swiper js ?
    //wp_enqueue_script();
  }

  public function initSidebar()
  {
    register_sidebar(
      array(
        'id'    => '',
        'name'  => '',
        'description' => ''
      )
    );

    register_widget( '' );
  }

  public function widget( $args, $instance )
  {
    ob_start();
    ?>

    <div class="swiper-container logo-slider" id="clients-logo-slider">
      <div class="swiper-wrapper" id="client-logo-wrapper">
        <!-- Здесь я хочу перебрать выбранные изображения, чтобы поместить их внутрь слайдера ? -->
        <img class="swiper-slide" src="" alt="" width="100" id="client-logo"/>

      </div>
      <div class="swiper-scrollbar"></div>
    </div>

    <?php
    echo ob_get_clean();
  }

  public function form( $instance )
  {
        $images = isset( $instance['images'] ) ?  $instance['images'] : '';
    ?>
    <p>
      <label for="<?php echo esc_attr($this->get_field_id('images')); ?>"><?php _e('Изображения слайдера'); ?></label>
    </p>
    <p style="display:flex;">
      <input type="text" class="widefat" id="<?php echo esc_attr($this->get_field_id('images')); ?>" name="<?php echo esc_attr($this->get_field_name('images')); ?>" value="<?php echo $images; ?>">
      <button type="button" class="button button-primary upload_image_button"><?php _e('Выбрать'); ?></button>
    </p>
    <?php
  }

  public function update( $new_instance, $old_instance )
  {
    $instance = $old_instance;
    // обновить код виджета 
    return $instance;
  }

}

Вот JS файлы, которые я использую для выбора изображения из медиатеки и которые не работают для множественного выбора, и встроенный код для настройки слайдера. Я помещу настройку слайдера в отдельный файл и использую wp_localize_script, чтобы передать пользовательские настройки, но я также подумываю оставить это встроенным.

// скрипт медиатеки
(function($){
  $(document).ready(function(){
    $(document).on('click', '.upload_image_button', function(e){
      e.preventDefault();
      var button = $(this);

      var file_frame = wp.media.frames.file_frame = wp.media({
        title: 'Выберите или загрузите изображение',
        library: {
          type: 'image'
        },
        button: {
          text: 'Выбрать'
        },
        multiple: true
      });

      file_frame.on('select', function(){
        var img = file_frame.state().get('selection').first().toJSON();
        button.siblings('input').val(img.url).change();
        console.log(img);
      });

      file_frame.open();
    });
  });
}(jQuery));

// настройка слайдера
(function($){
  $(document).ready(function(){
    var swiperLogos = new Swiper('.logo-slider',{
      autoplay: {
      delay: 3000,
      },
      slidesPerView: 'auto',
      slidesPerColumnFill: 'row',
      scrollbar: {
        el: '.swiper-scrollbar',
        draggable: true,
      },
    });
  });
}(jQuery));

Я сам нашел решение!
С помощью двух строк кода я теперь могу сохранить все выбранные изображения и затем извлекать их на фронтенде.

Я добавил массив в часть кода JS:

// скрипт медиатеки
(function($){
  $(document).ready(function(){
    $(document).on('click', '.upload_image_button', function(e){
      e.preventDefault();
      var button = $(this);

      var file_frame = wp.media.frames.file_frame = wp.media({
        title: 'Выберите или загрузите изображение',
        library: {
          type: 'image'
        },
        button: {
          text: 'Выбрать'
        },
        multiple: true
      });

      file_frame.on('select', function(){
        var img = file_frame.state().get('selection');
        var urls = []; 
        img.each(function(selection){
        urls.push(selection.attributes.url)
        button.siblings('input').val(urls).change();
        });
      });

      file_frame.open();
    });
  });
}(jQuery));

Затем в php части я реализовал explode() и цикл foreach(), чтобы получить сохраненные URL и поместить их внутрь тега img слайдера:

public function widget( $args, $instance )
  {
    $images = explode( ',', $instance['images'] );
    ob_start();
    ?>
    <div class="swiper-container logo-slider" id="featured-logo-slider">
      <div class="swiper-wrapper" id="featured-logo">
        <?php foreach( $images as $image ): ?>
          <img class="swiper-slide" src="https://wordpress.stackexchange.com/questions/355953/<?php echo $image; ?>" alt="" width="100" id="client-logo"/>
        <?php endforeach; ?>
      </div>
      <div class="swiper-scrollbar"></div>
    </div>
    <?php
    echo ob_get_clean();
  }

Ответ или решение

Создание пользовательского виджета выбора нескольких изображений для карусели на WordPress является достаточно распространенной задачей. В вашем случае вы хотите widget’изировать компонент слайдера логотипов, использующий библиотеку медиа для выбора изображений. Вот как это можно сделать, шаг за шагом.

Шаг 1: Создание класса виджета

Ваш класс виджета должен наследовать WP_Widget и иметь необходимые методы для настройки и отображения. Я добавлю необходимые изменения к вашему классу FeaturedLogoSlider.

class FeaturedLogoSlider extends WP_Widget {

  public function __construct() {
    parent::__construct(
      'featured-brands',
      'Featured Brands Slider',
      array('description' => __('Featured brands logos slider', ''))
    );
    add_action('widgets_init', array($this, 'initSidebar'));
    add_action('wp_enqueue_scripts', array($this, 'initScripts'));
  }

  public function initScripts() {
    wp_enqueue_media();
    wp_enqueue_script('medialib-script', plugins_url('medialib-script.min.js', __FILE__), array('jquery'), null);
  }

  public function initSidebar() {
    register_sidebar(array(
      'id' => 'featured_brands',
      'name' => __('Featured Brands', 'text_domain'),
      'description' => __('A slider for featured brands logos', 'text_domain')
    ));
    register_widget('FeaturedLogoSlider');
  }

  public function widget($args, $instance) {
    $images = explode(',', $instance['images']);
    ob_start(); 
    ?>
    <div class="swiper-container logo-slider" id="clients-logo-slider">
      <div class="swiper-wrapper" id="client-logo-wrapper">
        <?php foreach ($images as $image): ?>
          <img class="swiper-slide" src="<?php echo esc_url(trim($image)); ?>" alt="" width="100" id="client-logo"/>
        <?php endforeach; ?>
      </div>
      <div class="swiper-scrollbar"></div>
    </div>
    <?php
    echo ob_get_clean();
  }

  public function form($instance) {
    $images = isset($instance['images']) ? $instance['images'] : '';
    ?>
    <p>
      <label for="<?php echo esc_attr($this->get_field_id('images')); ?>"><?php _e('Slider Images', 'text_domain'); ?></label>
    </p>
    <p style="display:flex;">
      <input type="text" class="widefat" id="<?php echo esc_attr($this->get_field_id('images')); ?>" name="<?php echo esc_attr($this->get_field_name('images')); ?>" value="<?php echo esc_attr($images); ?>" />
      <button type="button" class="button button-primary upload_image_button"><?php _e('Select', 'text_domain'); ?></button>
    </p>
    <?php
  }

  public function update($new_instance, $old_instance) {
    $instance = $old_instance;
    $instance['images'] = sanitize_text_field($new_instance['images']);
    return $instance;
  }
}

Шаг 2: JavaScript для выбора изображений

Ваша логика для выбора изображений из библиотеки медиа должна поддерживать множественный выбор. Вы уже частично реализовали это, но я внесу некоторые улучшения.

(function($) {
  $(document).ready(function() {
    $(document).on('click', '.upload_image_button', function(e) {
      e.preventDefault();
      var button = $(this);

      var file_frame = wp.media({
        title: 'Select or Upload Images',
        library: {
          type: 'image'
        },
        button: {
          text: 'Select'
        },
        multiple: true
      });

      file_frame.on('select', function() {
        var img = file_frame.state().get('selection');
        var urls = [];
        img.each(function(selection) {
          urls.push(selection.attributes.url);
        });
        button.siblings('input').val(urls.join(',')).change(); // Записываем URL-адреса как строку
      });

      file_frame.open();
    });
  });
})(jQuery);

Шаг 3: Обработка изображений в PHP

В методе widget ваши URL-адреса изображений должны быть распарсены и возвращены в слайдер.

Вы уже правильно используете explode() для разделения строк на массив.

Шаг 4: Регистрация виджета

На вашем сайте WordPress используйте функцию register_widget() для регистрации нового виджета в initSidebar.

Шаг 5: Включение и инициализация слайдера Swiper

Убедитесь, что скрипты Swiper включены и инициализированы. Объявите слайдер в вашем JavaScript, чтобы инициализировать его после загрузки изображений.

(function($) {
  $(document).ready(function() {
    var swiperLogos = new Swiper('.logo-slider', {
      autoplay: {
        delay: 3000,
      },
      slidesPerView: 'auto',
      scrollbar: {
        el: '.swiper-scrollbar',
        draggable: true,
      },
    });
  });
})(jQuery);

Заключение

Теперь у вас есть полный код для создания пользовательского виджета логотипов с поддержкой множественного выбора изображений. Это решение позволяет использовать медиа-библиотеку WordPress для добавления логотипов в слайдер, обеспечивая хорошую гибкость и простоту использования. Не забудьте протестировать реализацию и убедиться, что все работает правильно!

Оцените материал
Добавить комментарий

Капча загружается...