WordPress как на ладони
wordpress jino

Миниатюры для элементов таксономий

В этой заметке я поделюсь готовым кодом, который добавляет возможность задавать миниатюры для элементов таксономий, как встроенных (метки, рубрики), так и произвольных. Код протестирован и 7 раз улучшен - все для вас, мои дорогие smile

Чтобы добавить, или загрузить и добавить, или изменить картинку элемента таксономии, нужно кликнуть на саму картинку - она по совместительству является кнопкой. При загрузке открывается стандартное окно медиафайлов и картинка загружается в медиатеку WordPress. Но в отличии от картинок записей, она не привязывается к термину - она не привязывается ни к чему и это минус. Ну, пока так.

По умолчанию код работает для всех публичных таксономий (рубрики, метки и существующие произвольные таксономии). В коде можно указать конкретные таксы для которых он должен работать.

Вот что мы получим в итоге:

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

Код

Можно сделать плагин или можно добавить его в functions.php темы.

<?php

/**
 * Возможность загружать изображения для элементов указанных таксономий: категории, метки.
 *
 * Пример получения ID и URL картинки термина:
 * $image_id = get_term_meta( $term_id, '_thumbnail_id', 1 );
 * $image_url = wp_get_attachment_image_url( $image_id, 'thumbnail' );
 *
 * @author: Kama (http://wp-kama.ru)
 *
 * @ver: 2.8
 */
if( is_admin() && ! class_exists('Term_Meta_Image') ){
	// init
	//add_action('current_screen', 'Term_Meta_Image_init');
	add_action('admin_init', 'Term_Meta_Image_init');
	function Term_Meta_Image_init(){
		$GLOBALS['Term_Meta_Image'] = new Term_Meta_Image();
	}

	class Term_Meta_Image {

		// для каких таксономий включить код. По умолчанию для всех публичных
		static $taxes = array(); // пример: array('category', 'post_tag');

		// название мета ключа
		static $meta_key = '_thumbnail_id';

		// URL пустой картинки
		static $add_img_url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEUAAAC7u7s37rVJAAAAAXRSTlMAQObYZgAAACJJREFUOMtjGAV0BvL/G0YMr/4/CDwY0rzBFJ704o0CWgMAvyaRh+c6m54AAAAASUVORK5CYII=';

		public function __construct(){
			if( isset($GLOBALS['Term_Meta_Image']) ) return $GLOBALS['Term_Meta_Image']; // once

			$taxes = self::$taxes ? self::$taxes : get_taxonomies( array( 'public'=>true ), 'names' );

			foreach( $taxes as $taxname ){
				add_action("{$taxname}_add_form_fields",   array( & $this, 'add_term_image' ),     10, 2 );
				add_action("{$taxname}_edit_form_fields",  array( & $this, 'update_term_image' ),  10, 2 );
				add_action("created_{$taxname}",           array( & $this, 'save_term_image' ),    10, 2 );
				add_action("edited_{$taxname}",            array( & $this, 'updated_term_image' ), 10, 2 );

				add_filter("manage_edit-{$taxname}_columns",  array( & $this, 'add_image_column' ) );
				add_filter("manage_{$taxname}_custom_column", array( & $this, 'fill_image_column' ), 10, 3 );
			}
		}

		## поля при создании термина
		public function add_term_image( $taxonomy ){
			wp_enqueue_media(); // подключим стили медиа, если их нет

			add_action('admin_print_footer_scripts', array( & $this, 'add_script' ), 99 );
			$this->css();
			?>
			<div class="form-field term-group">
				<label><?php _e('Image', 'default'); ?></label>
				<div class="term__image__wrapper">
					<a class="termeta_img_button" href="#">
						<img src="<?php echo self::$add_img_url ?>" alt="">
					</a>
					<input type="button" class="button button-secondary termeta_img_remove" value="<?php _e( 'Remove', 'default' ); ?>" />
				</div>

				<input type="hidden" id="term_imgid" name="term_imgid" value="">
			</div>
			<?php
		}

		## поля при редактировании термина
		public function update_term_image( $term, $taxonomy ){
			wp_enqueue_media(); // подключим стили медиа, если их нет

			add_action('admin_print_footer_scripts', array( & $this, 'add_script' ), 99 );

			$image_id = get_term_meta( $term->term_id, self::$meta_key, true );
			$image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'thumbnail' ) : self::$add_img_url;
			$this->css();
			?>
			<tr class="form-field term-group-wrap">
				<th scope="row"><?php _e( 'Image', 'default' ); ?></th>
				<td>
					<div class="term__image__wrapper">
						<a class="termeta_img_button" href="#">
							<?php echo '<img src="'. $image_url .'" alt="">'; ?>
						</a>
						<input type="button" class="button button-secondary termeta_img_remove" value="<?php _e( 'Remove', 'default' ); ?>" />
					</div>

					<input type="hidden" id="term_imgid" name="term_imgid" value="<?php echo $image_id; ?>">
				</td>
			</tr>
			<?php
		}

		public function css(){
			?>
			<style>
				.termeta_img_button{ display:inline-block; margin-right:1em; }
				.termeta_img_button img{ display:block; float:left; margin:0; padding:0; min-width:100px; max-width:150px; height:auto; background:rgba(0,0,0,.07); }
				.termeta_img_button:hover img{ opacity:.8; }
				.termeta_img_button:after{ content:''; display:table; clear:both; }
			</style>
			<?php
		}

		## Add script
		public function add_script(){
			// выходим если не на нужной странице таксономии
			//$cs = get_current_screen();
			//if( ! in_array($cs->base, array('edit-tags','term')) || ! in_array($cs->taxonomy, (array) $this->for_taxes) )
			//  return;

			$title = __('Featured Image', 'default');
			$button_txt = __('Set featured image', 'default');
			?>
			<script>
			jQuery(document).ready(function($){
				var frame,
					$imgwrap = $('.term__image__wrapper'),
					$imgid   = $('#term_imgid');

				// добавление
				$('.termeta_img_button').click( function(ev){
					ev.preventDefault();

					if( frame ){ frame.open(); return; }

					// задаем media frame
					frame = wp.media.frames.questImgAdd = wp.media({
						states: [
							new wp.media.controller.Library({
								title:    '<?php echo $title ?>',
								library:   wp.media.query({ type: 'image' }),
								multiple: false,
								//date:   false
							})
						],
						button: {
							text: '<?php echo $button_txt ?>', // Set the text of the button.
						}
					});

					// выбор
					frame.on('select', function(){
						var selected = frame.state().get('selection').first().toJSON();
						if( selected ){
							$imgid.val( selected.id );
							$imgwrap.find('img').attr('src', selected.sizes.thumbnail.url );
						}
					} );

					// открываем
					frame.on('open', function(){
						if( $imgid.val() ) frame.state().get('selection').add( wp.media.attachment( $imgid.val() ) );
					});

					frame.open();
				});

				// удаление
				$('.termeta_img_remove').click(function(){
					$imgid.val('');
					$imgwrap.find('img').attr('src','<?php echo self::$add_img_url ?>');
				});
			});
			</script>

			<?php
		}

		## Добавляет колонку картинки в таблицу терминов
		public function add_image_column( $columns ){
			// подправим ширину колонки через css
			add_action('admin_notices', function(){
				echo '<style>.column-image{ width:50px; text-align:center; }</style>';
			});

			$num = 1; // после какой по счету колонки вставлять

			$new_columns = array( 'image'=>'' ); // колонка без названия...

			return array_slice( $columns, 0, $num ) + $new_columns + array_slice( $columns, $num );
		}

		public function fill_image_column( $string, $column_name, $term_id ){
			// если есть картинка
			if( $image_id = get_term_meta( $term_id, self::$meta_key, 1 ) )
				$string = '<img src="'. wp_get_attachment_image_url( $image_id, 'thumbnail' ) .'" width="50" height="50" alt="" style="border-radius:4px;" />';

			return $string;
		}

		## Save the form field
		public function save_term_image( $term_id, $tt_id ){
			if( isset($_POST['term_imgid']) && $image = (int) $_POST['term_imgid'] )
				add_term_meta( $term_id, self::$meta_key, $image, true );
		}

		## Update the form field value
		public function updated_term_image( $term_id, $tt_id ){
			if( ! isset($_POST['term_imgid']) ) return;

			if( $image = (int) $_POST['term_imgid'] )
				update_term_meta( $term_id, self::$meta_key, $image );
			else
				delete_term_meta( $term_id, self::$meta_key );
		}

	}

}
/**
 * 2.8 - исправил ошибку удаления картинки.
 */

Вывод картинки элемента таксономии во фронтенде

Бэкграунд для добавления картинки у нас есть, теперь осталось понять как получать такие картинки терминов в лицевой части сайта.

Делается это через родную функцию WordPress get_term_meta(), которая напомню еще раз существует с версии 4.4.

ID картинок (вложений) сохраняется в метаполе термина _thumbnail_id, его и будем получать.

// получаем ID термина на странице термина
$term_id = get_queried_object_id();

// получим ID картинки из метаполя термина
$image_id = get_term_meta( $term_id, '_thumbnail_id', 1 );

// ссылка на полный размер картинки по ID вложения
$image_url = wp_get_attachment_image_url( $image_id, 'full' );

// выводим картинку на экран
echo '<img src="'. $image_url .'" alt="" />';

Если нужен не полный размер меняем full на нужный размер в wp_get_attachment_image_url(). Если нужны другие данные картинки, используем другую функцию получения вложения по ID.

Плагины для вставки миниатюр таксономий

Не кодом единым жив программист - есть еще плагины:

  • Taxonomy Thumbnail - по коду все круто, только его там много. Поддержка версий WP до 4,4 (когда была добавлена таблица метаданных таксономий)...

  • WP Multiple Taxonomy Images - код плагина очень похож на код из этой статьи - его не много, только то что нужно. Фишка плагина в том, что он позволяет задать сразу несколько миниатюр для термина.

  • Taxonomy Images - самый рейтинговый плагин по этому вопросу. Плагин в целом неплохой, но кода много, «лишнего» много, кажется. Если лишнее не нужно, используйте лучше предыдущие плагины или код из этой статьи.
Миниатюры для элементов таксономий 19 комментариев
Полезные 1 Вопросы 2 Все
  • еще для категорий связка плагинов ACF + ACFCategories тоже сделает + дополнительные поля какие угодно.

    1
  • Каратъ

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

    • Kama4697

      Проверил еще раз, все работает... Может у тебя какой-то другой плагин конфликтует? unknw

  • Владимир cайт: www.korvet2.ru @

    Здравствуйте!
    Статья очень полезная и познавательная. Прочитал с большим интересом. У меня на блоге миниатюры выводятся у каждой статьи в разделе похожие записи, а также для страниц меток (TAG). Все работает хорошо, но есть вопрос. Миниатюры я создавал и прикреплял через админку. Каждую миниатюру делал строго нужного размера и минимального веса. При этом в админке создается миниатюра с адресом, например, хххх.png, а на странице блога выводится с адресом хххх 140х120.png 140х120 – это размеры миниатюры. Если посмотреть по FTP содержание папки миниатюр, то и там каждой миниатюре соответствует два файла с указанными адресами, но разного веса. Нужно ли это? Очень сильное подозрение, что я сделал что-то не так. Подскажите, пожалуйста, как должно быть и где искать?

    • Kama4697

      Как могут в папке находится 2 файла с одинаковыми названиями? Может вторая картинка для ретина дисплеев? И при заливке создается еще и такая копия. Если это так, то нужно это или нет решать вам - наверное нет.

  • Андрей

    Почему то не работает код не выводит миниаютуру рубрики

    ?php if($children_categories): // если есть дочерние категории ?>
    	<?php foreach($children_categories as $children_category): ?>
    	<?php $link = get_category_link( $children_category->cat_ID ); ?>
    	<?php $image_url = wp_get_attachment_image_url( $image_id, 'thumbnail' ); ?>
    	<div class="item2" id="bx_3966226736_675">
    		<a class="gallery2" href="<?php echo $link; ?>">
    			<img src="<?=$image_url;?>" alt="<?=$children_category->name;?>" height="158">
    		</a>
    		<div class="pevu_title"><p><?=$children_category->name;?></p></div>
    	</div>
    <?php endforeach; ?>

    Весь код

    <?php get_header(); ?>
    
    <?php
    // номер рубрики
    $category_id = get_query_var( 'cat' );
    // номер текущей страницы
    $page = get_query_var( 'paged' );
    // данные о текущей категории
    $category = get_category( $category_id );
    // данные о дочерних рубриках
    $children_categories = get_categories( array(
    	'child_of' => $parent_id,
    	'hide_empty' => 0,
    	'parent' => $category_id, 
    ) );
    ?>
    
    <section>
    
    <div class="container-fluid transport_bgsilver">
    		<div class="container">
    				<div class="row">
    					<div class="col-md-12 text_otstup">
    
    <div class="h1">
    <h1 class="categoryh"><?=$category->name;?></h1>
    </div>
    
    <center>
    <?php if($children_categories): // если есть дочерние категории ?>
    	<?php foreach($children_categories as $children_category): ?>
    	<?php $link = get_category_link( $children_category->cat_ID ); ?>
    
    	<div class="item2" id="bx_3966226736_675">
    		<a class="gallery2" href="<?php echo $link; ?>">
    			<img src="<?php echo $img_urls ;?>" alt="<?=$children_category->name;?>" height="158">
    		</a>
    		<div class="pevu_title"><p><?=$children_category->name;?></p></div>
    	</div>
    <?php endforeach; ?>
    <?php else:  ?>
      <?php if ( have_posts() ) :?>
    
      <div class="col-md-12 text_otstup">
      <?php while ( have_posts() ) : the_post(); ?>
    
      <div class="item">
    	   <a class="gallery" href="#">
    			<?php the_post_thumbnail('', array('class' => 'catimages')); ?>
    		</a>
    		<div class="pevu_title"><p><?php echo (get_post_meta($post->ID, 'type', true)); ?></p></div>
    		<div class="pruv_text">
    		  <p>Цена: <span>от <?php echo (get_post_meta($post->ID, 'cena', true)); ?> грн. </span></p>
    	   </div>
    	</div>
    
    	<?php endwhile; ?>
    	  </div>
    	<?php else: ?>
    	<!-- no posts found -->
    	<?php endif; ?>
    	<?php wp_reset_postdata(); ?>
    
    <?php endif; ?>
    
    </center>
    
    		</div>
    	</div>
    </div>
    </div>
    
    </section>
    
    <?php get_footer(); ?>
  • Почему-то миниатюру удалить не получается, при нажатии удалить удаляется, но после обновления рубрики снова появляется, при этом заменить ее на другую можно. Пробовал на нескольких темах, в том числе и на стандартной ВП, но тот же результат

    Ответить3 месяца назад #
  • Вот еще хороший плагин отыскал, минимум кона и ничего лишнего. Работает со старыми и новыми версиями ВП. Добавляет произвольное поле, в которое встраивает ссылку на картинку.
    Плагин называется categories-images
    Ссылку в разделе рубрики выводит вот так
    echo z_taxonomy_image_url($cat->term_id, 'full');

    1
    Ответить3 месяца назад #
  • Александр
    ## Update the form field value
    	public function updated_term_image( $term_id, $tt_id ){
    	if( empty($_POST['term_imgid']) ) return;
    
    	if( $image = (int) $_POST['term_imgid'] )
    		update_term_meta( $term_id, self::$meta_key, $image );
    	else
    		delete_term_meta( $term_id, self::$meta_key );
    }

    Картинку невозможно обновить условие
    if( empty($_POST['term_imgid']) ) return;
    Не пропускает изменения его необходимо просто убрать из кода, так как при удалении как раз пустое поле, спасибо за ваше решение!

    Ответить2 месяца назад #
    • Kama4697

      Поправил - версия 2.8. Спасибо большое за коммент! Убрать из кода это можно, но не рекомендую, лучше правильно проверить.

      Ответить2 месяца назад #
  • Андрей @

    Здравствуйте, меня интересует вопрос для вывода миниатюры с дочерних рубрик. Как это можно реализовать?
    Т.е. заходим в рубрику, а там списком идет вывод дочерних, что лежат внутри главной рубрики и к ним их миниатюры. Спасибо за ранее.

    3
    Ответить2 месяца назад #
    • Антон

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

      Ответитьмесяц назад #
    • Kama4697

      Получаешь метаполе термина где хранится миниатюра. Не понял вопрос, в чем сложность?

      Ответитьмесяц назад #
      • Антон

        Сложность в том, что я, к примеру, не очень хорошо разбираюсь в PHP.
        Те примеры, которые смотрел — привязаны к id рубрики, а нужно, чтобы построение шло динамически. Т.е. заходим в родительскую — там дочерние с миниатюрами, заходим в дочернюю — там внучки, тоже с миниатюрами и т.д.
        Вот например код вывода изображений рубрик с помощью плагина Taxonomy Images,
        но выводит он все рубрики, а не только дочерние. И причем все в кучу, даже не разбивая на подсписки.

        /* вывод списка рубрик */
        $args = array(
        	'parent' => 0,
        	'hide_empty' => 0,
        	'exclude' => '', // ID рубрики, которую нужно исключить
        	'number' => '0',
        	'taxonomy' => 'category', // таксономия, для которой нужны изображения
        	'pad_counts' => true
        );
        $catlist = get_categories($args); // получаем список рубрик
        
        foreach($catlist as $categories_item)
        	{
        	// получаем данные из плагина Taxonomy Images
        	$terms = apply_filters('taxonomy-images-get-terms', '', array(
        		'taxonomy' => 'category' // таксономия, для которой нужны изображения
        	));
        	if (!empty($terms))
        		{
        		foreach((array)$terms as $term)
        			{
        			if ($term->term_id == $categories_item->term_id)
        				{
        				// выводим изображение рубрики
        				print '<a href="' . esc_url(get_term_link($term, $term->taxonomy)) . '" title="Нажмите, чтобы перейти в рубрику">' . wp_get_attachment_image($term->image_id, 'thumbnail');
        				echo '</a>';
        				}
        			}
        		}
        	// выводим описание и название рубрики
        	echo "<li><a href=\"#\">" . $categories_item->cat_name . "</a><br /><span class=\"small-text\">" . $categories_item->category_description . "</span></li>";
        	}

        Может подскажите более качественное решение этого вопроса?

        Ответить28 дней назад #
        • Kama4697

          На странице рубрики только код работать должен. Указываешь

          'parent' => get_queried_object_id(),

          получим только дочерние рубрики к текущей. Миниатюру выводим через

          wp_get_attachment_image( get_term_meta( $term->term_id, '_tumbnail_id', 1 ) );
          Ответить28 дней назад #
          • Антон

            Спасибо большое за подсказку
            Проблема осталась в этом месте

            echo "<li><a href=\"#\">" . $categories_item->cat_name . "</a><br /><span class=\"small-text\">" . $categories_item->category_description . "</span></li>";

            Ссылается на #

            Ответить27 дней назад #
          • Антон

            Решил задачу следующим образом — может кому пригодится.
            Необходим плагин Taxonomy Images

            <?php 
            /* вывод списка рубрик */
            $args = array(
            	'parent' => get_queried_object_id(),
            	'hide_empty' => 0,
            	'exclude' => '', // ID рубрики, которую нужно исключить
            	'number' => '0',
            	'taxonomy' => 'category', // таксономия, для которой нужны изображения
            	'pad_counts' => true
            );
            $catlist = get_categories($args); // получаем список рубрик
            
            foreach($catlist as $categories_item)
            	{
            	// получаем данные из плагина Taxonomy Images
            	$terms = apply_filters('taxonomy-images-get-terms', '', array(
            		'taxonomy' => 'category' // таксономия, для которой нужны изображения
            	));
            	if (!empty($terms))
            		{
            		foreach((array)$terms as $term)
            			{
            			if ($term->term_id == $categories_item->term_id)
            				{
            				// выводим изображение рубрики
            				print '<div class="subcat"><a href="' . esc_url(get_term_link($term, $term->taxonomy)) . '" title="Нажмите, чтобы перейти в рубрику">' . wp_get_attachment_image($term->image_id, 'medium');
            				echo  "<div class='rub'>$categories_item->cat_name </div></a></div>";
            				}
            			}
            		}
            	// выводим описание и название рубрики
            	//echo "<li><a href='" . esc_url(get_term_link($term, $term->taxonomy)) . "'>" . $categories_item->cat_name . "</a></li>";
            	}
            ?>
            Ответить27 дней назад #
  • а можно сделать это только для определенного типа записи?

    Ответитьмесяц назад #
    • все) разобрался) спасибо) не обратил внимания сначало где ввести название таксономии)

      1
      Ответитьмесяц назад #

Здравствуйте, !

Ваш комментарий
Предпросмотр