Вывод категорий с миниатюрами и описанием на главной странице
Мне действительно нужно комплексное решение, поэтому я предлагаю почти четверть своей репутации в качестве награды :)
Я хотел бы иметь плагин, который создает кастомный список категорий на главной странице. Для этого мне нужно расширить функциональность экрана "Редактирование категории" следующим образом...
- Добавляет обработчик "Загрузить/Удалить изображение" на экран редактирования категории (это позволит пользователям загружать изображение, которое будет представлять категорию. Идеально, если плагин автоматически изменяет размер изображения до 125 пикселей в ширину при загрузке).
- Добавляет поле ввода "Заголовок категории" на экран редактирования категории (в дополнение к стандартному полю "Название").
- Добавляет чекбокс "Показывать в списке на главной" для выборочного отображения категорий в списке на главной странице.
- При просмотре главной страницы плагин добавляет к the_content кастомный список категорий, включая миниатюру и заголовок каждой категории.
Результирующая разметка должна быть неупорядоченным списком без вложений, например:
<ul class="custom-categories">
<li>
<span><a href="link-to-category-1"><img src="the-category-1-image" /></a></span>
<a href="link-to-category-1">Название категории 1</a> Текст описания категории
</li>
<li>
<span><a href="link-to-category-2"><img src="the-category-2-image" /></a></span>
<a href="link-to-category-2">Название категории 2</a> Текст описания категории
</li>
и т.д...
</ul>
Вот заготовка кода, с которой я начал...
add_filter( 'the_content', 'cb_category_listing' );
function cb_category_listing( $content )
{
if ( is_home() ) {
$cat_args['title_li'] = '';
$cat_args['exclude_tree'] = 1;
$cat_args['exclude'] = 1;
$myContent = wp_list_categories(apply_filters('widget_categories_args', $cat_args));
$content .= $myContent;
}
return $content;
}

Примечание: Это для старых версий WP < 3.9 до внедрения новой загрузки медиафайлов
Вот как добавить поля и сохранить значения на экране редактирования категорий, а также метод добавления поля загрузки изображения.
Добавление полей на экран редактирования категории
Для начала нам нужно отобразить некоторый код на экране редактирования категории.
add_action( 'edit_category_form_fields', 'my_category_custom_fields' );
add_action( 'edit_category', 'save_my_category_custom_fields' );
function my_category_custom_fields( $tag ) {
// здесь будет ваш HTML для пользовательских полей
// переменная $tag - это объект термина таксономии со свойствами $tag->name, $tag->term_id и т.д.
// нам нужно знать значения существующих записей, если они есть
$category_meta = get_option( 'category_meta' );
?>
<tr class="form-field">
<th scope="row" valign="top"><label for="category-title"><?php _e("Заголовок"); ?></label></th>
<td>
<input id="category-title" name="category_meta[<?php echo $tag->term_id ?>][title]" value="<?php if ( isset( $category_meta[ $tag->term_id ] ) ) esc_attr_e( $category_meta[ $tag->term_id ]['title'] ); ?>" />
<span class="description"><?php _e('Введите альтернативный заголовок для этой категории.'); ?></span>
</td>
</tr>
<!-- повторяем для других необходимых полей -->
<?php
}
Самый простой способ хранить наши пользовательские значения - в таблице опций (на самом деле должна быть таблица таксономия-мета, но неважно). Таким образом, нам нужно выполнить только один запрос, чтобы получить метаданные для всех наших категорий. Если у кого-то есть лучшая идея для хранения, высказывайтесь!
function save_my_category_custom_fields() {
if ( isset( $_POST['category_meta'] ) && !update_option('category_meta', $_POST['category_meta']) )
add_option('category_meta', $_POST['category_meta']);
}
Для чекбокса вы просто храните true или false, поэтому используйте category_extras[$tag->term_id][show_on_home]
для атрибута name и используйте значение, хранящееся в $category_meta
, чтобы определить, отмечен он или нет.
Вы можете добавить дополнительную обработку или санитацию в функцию сохранения - мой пример просто быстрый и грязный.
Поле изображения
Это довольно много кода и довольно сложно, поэтому я не буду объяснять все здесь, но комментарии описывают назначение каждой функции. Мы можем обсудить в комментариях, если хотите.
Следующие функции добавляют ссылку на экран редактирования категории, которая вызывает всплывающее окно медиабиблиотеки WordPress/загрузки изображений. Затем вы можете загрузить картинку и нажать, чтобы использовать ее. Затем у вас будет доступен ID изображения и URL миниатюры вместе с другими метаданными выше.
// добавляем нужный размер изображения
add_image_size( 'category_thumb', 125, 125, true );
// настраиваем наше поле изображения и методы обработки
function setup_category_image_handling() {
// добавляем поле изображения к остальным
add_action( 'edit_category_form_fields', 'category_image' );
global $pagenow;
if ( is_admin() ) {
add_action( 'admin_init', 'fix_async_upload_image' );
if ( 'edit-tags.php' == $pagenow ) {
add_thickbox();
add_action('admin_print_footer_scripts', 'category_image_send_script', 1000);
} elseif ( 'media-upload.php' == $pagenow || 'async-upload.php' == $pagenow ) {
add_filter( 'media_send_to_editor', 'category_image_send_to_editor', 1, 8 );
add_filter( 'gettext', 'category_image_replace_text_in_thickbox', 1, 3 );
}
}
}
add_action( 'admin_init', 'setup_category_image_handling' );
// поле изображения на экране редактирования таксономии
function category_image( $tag ) {
// получаем наши метаданные категории
$category_meta = get_option('category_meta');
?>
<tr class="form-field hide-if-no-js">
<th scope="row" valign="top"><label for="taxonomy-image"><?php _e("Изображение"); ?></label></th>
<td>
<div id="taxonomy-image-holder">
<?php if( !empty($category_meta[$tag->term_id]['image']) ) { ?>
<img style="max-width:100%;display:block;" src="<?php echo esc_attr( $category_meta[ $tag->term_id ]['image']['thumb'] ); ?>" alt="Миниатюра категории" title="Миниатюра категории" />
<a id="taxonomy-image-select" class="thickbox" href="media-upload.php?is_term=true&type=image&TB_iframe=1"><?php _e('Изменить изображение'); ?></a>
<a class="deletion" id="taxonomy-image-remove" href="#remove-image">Удалить изображение</a>
<?php } else { ?>
<a id="taxonomy-image-select" class="thickbox" href="media-upload.php?is_term=true&type=image&TB_iframe=1"><?php _e('Выбрать изображение'); ?></a>
<?php } ?>
</div>
<input type="hidden" name="category_meta[<?php echo $tag->term_id ?>][image][id]" value="<?php if( isset($category_meta[ $tag->term_id ]['image']['id']) ) echo esc_attr($category_meta[ $tag->term_id ]['image']['id']); ?>" class="tax-image-id" />
<input type="hidden" name="category_meta[<?php echo $tag->term_id ?>][image][thumb]" value="<?php if( isset($category_meta[ $tag->term_id ]['image']['thumb']) ) echo esc_attr($category_meta[ $tag->term_id ]['image']['thumb']); ?>" class="tax-image-thumb" />
<span class="description"><?php _e('Изображение категории.'); ?></span></td>
</tr>
<?php
}
// необходимо для загрузки изображений на экранах, не связанных с записями/страницами
function fix_async_upload_image() {
if(isset($_REQUEST['attachment_id'])) {
$GLOBALS['post'] = get_post($_REQUEST['attachment_id']);
}
}
// работаем с экраном редактирования таксономии?
function is_category_context() {
if ( isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'],'is_term') !== false ) {
return true;
} elseif ( isset($_REQUEST['_wp_http_referer']) && strpos($_REQUEST['_wp_http_referer'],'is_term') !== false ) {
return true;
} elseif ( isset($_REQUEST['is_term']) && $_REQUEST['is_term'] !== false ) {
return true;
}
return false;
}
// заменяем текст "Вставить в запись" на более подходящий
function category_image_replace_text_in_thickbox($translated_text, $source_text, $domain) {
if ( is_category_context() ) {
if ('Insert into Post' == $source_text) {
return __('Использовать это изображение', MB_DOM );
}
}
return $translated_text;
}
// выводим скрипт, который устанавливает переменные в объекте window, чтобы к ним можно было получить доступ в других местах
function category_image_send_to_editor( $html, $id, $attachment ) {
// проверка контекста может быть не обязательной и может не работать во всех случаях
if ( is_category_context() ) {
$item = get_post($id);
$src = wp_get_attachment_image_src($id,'thumbnail',true); // 0 = url, 1 = ширина, 2 = высота, 3 = иконка (bool)
?>
<script type="text/javascript">
// отправляем переменные изображения обратно в opener
var win = window.dialogArguments || opener || parent || top;
win.TI.id = <?php echo $id ?>;
win.TI.thumb = '<?php echo $src[0]; ?>';
</script>
<?php
}
return $html;
}
// выводим javascript, который обрабатывает действия при нажатии пользователем на использование изображения
function category_image_send_script() { ?>
<script>
self.TI = {};
var tb_position;
function send_to_editor(h) {
// игнорируем контент, возвращаемый из загрузчика медиа, и используем переменные, переданные в window
jQuery('.tax-image-id').val( self.TI.id );
jQuery('.tax-image-thumb').val( self.TI.thumb );
// отображаем изображение
jQuery('#taxonomy-image-holder img, #taxonomy-image-remove').remove();
jQuery('#taxonomy-image-holder')
.prepend('<img style="max-width:100%;display:block;" src="'+ self.TI.thumb +'" alt="Миниатюра категории" title="Миниатюра категории" />')
.append('<a class="deletion" id="taxonomy-image-remove" href="#remove-image">Удалить изображение</a>');
jQuery('#taxonomy-image-select').html('Изменить изображение');
// закрываем thickbox
tb_remove();
}
(function($){
$(document).ready(function() {
tb_position = function() {
var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 720 < width ) ? 720 : width;
if ( tbWindow.size() ) {
tbWindow.width( W - 50 ).height( H - 45 );
$('#TB_iframeContent').width( W - 50 ).height( H - 75 );
tbWindow.css({'margin-left': '-' + parseInt((( W - 50 ) / 2),10) + 'px'});
if ( typeof document.body.style.maxWidth != 'undefined' )
tbWindow.css({'top':'20px','margin-top':'0'});
};
return $('a.thickbox').each( function() {
var href = $(this).attr('href');
if ( ! href ) return;
href = href.replace(/&width=[0-9]+/g, '');
href = href.replace(/&height=[0-9]+/g, '');
$(this).attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 ) );
});
};
$(window).resize(function(){ tb_position(); });
$('#taxonomy-image-select').click(function(event){
tb_show("Выбрать изображение:", $(this).attr("href"), false);
return false;
});
$('#taxonomy-image-remove').live('click',function(event){
$('#taxonomy-image-select').html('Выбрать изображение');
$('#taxonomy-image-holder img').remove();
$('input[class^="tax-image"]').val("");
$(this).remove();
return false;
});
});
})(jQuery);
</script>
<?php
}
Доступ к информации
В вашей функции my_function
, взятой из вашего собственного ответа, вы можете получить доступ к метаданным следующим образом:
function my_function(){
$args=array(
'orderby' => 'name',
'order' => 'ASC'
);
$categories=get_categories($args);
// получаем наши метаданные категории и выходим, если их нет
$category_meta = get_option('category_meta');
if ( !$category_meta )
return;
echo '<ul style="list-style-type:none;margin:0;padding:0">';
foreach($categories as $category) {
// пропускаем неотмеченные категории и категории без метаданных
if ( !isset( $category_meta[ $category->term_id ] ) || ( isset( $category_meta[ $category->term_id ] ) && !$category_meta[ $category->term_id ]['show_on_home'] ) )
continue;
echo '<li><a style="display:block;margin-top:20px;" href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Просмотреть все записи в %s" ), $category->name ) . '" ' . '>' . $category_meta[ $category->term_id ]['title'].'</a>';
if ( "" != $category_meta[ $category->term_id ]['image']['id'] )
echo wp_get_attachment_image( $category_meta[ $category->term_id ]['image']['id'], 'category_thumbnail', false, array( 'alt' => $category->name, 'class' => '' ) );
echo $category->description . '</li>';
}
echo '</ul>';
}

Вау, спасибо sanchothefat. Я ценю твои усилия. Я уже собрал большую часть сам, но я приму твой ответ и внедрю его в свой код.

Sanchothefat, ты заслуживаешь вознаграждение, которое я установил за этот вопрос. Ты его получил?

Насколько сложно будет изменить твой код, чтобы сохранять изображения в папку "category-images" внутри uploads? И если папка не существует - создать ее.

Честно говоря, я не уверен. Возможно, существует фильтр для пути к директории загрузки. Но лично я предпочитаю использовать встроенную медиатеку, так как она значительно упрощает процесс загрузки и генерации миниатюр. Посмотрите http://adambrown.info/p/wp_hooks - это отличный ресурс, где описаны все хуки и фильтры в WordPress.
Я не получил награду :( наверное, срок истек.

Простой способ — использовать что-то вроде этого http://wordpress.org/extend/plugins/category-images/. Или вы можете написать собственный хук.

Спасибо, Уик, я протестировал этот плагин, но он не делает ВСЕ, что мне нужно. Например, я не хочу заменять текст ссылки на изображение, мне нужно и изображение, И текст ссылки.

Похоже, что миниатюра отображается только на странице single.php для записи. Мне нужен пользовательский список категорий (что-то вроде индексной страницы) для всех категорий. Я обновил свой вопрос с более конкретными деталями и добавил награду за окончательное решение.

Это была моя первая попытка...
add_filter( 'the_content', 'cb_category_listing' );
function cb_category_listing( $content )
{
if ( is_home() ) {
$cat_args['title_li'] = '';
$cat_args['exclude_tree'] = 1;
$cat_args['exclude'] = 1;
$myContent = wp_list_categories(apply_filters('widget_categories_args', $cat_args));
$content .= $myContent;
}
return $content;
}
Очевидно, что это просто создает список названий категорий со ссылкой на каждую категорию. Это дает мне старт. Однако мне все еще нужно...
Способ связать миниатюру категории с каждой категорией и отображать ее в списке категорий в моем коде выше.
Способ включить пользовательский заголовок категории, отличный от имени категории, и отображать его в списке категорий (вместо "Название категории").
Способ показывать/скрывать каждую категорию из списка. В идеале, с чекбоксом "Показывать в списке на главной странице", который можно редактировать на экране редактирования категории.
Вот мой обновленный код. Продвигаюсь, но еще не разобрался с миниатюрой или добавлением пользовательских полей (миниатюра, пользовательский заголовок, показ/скрытие) в админке редактора категорий...
function _add_my_filter() {
if ( is_home() OR is_sticky() )
{
add_filter( 'the_content', 'my_function' );
}
}
add_action('template_redirect', '_add_my_filter');
function my_function(){
$args=array(
'orderby' => 'name',
'order' => 'ASC'
);
$categories=get_categories($args);
echo '<ul style="list-style-type:none;margin:0;padding:0">';
foreach($categories as $category) {
echo '<li><a style="display:block;margin-top:20px;" href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "Просмотреть все записи в %s" ), $category->name ) . '" ' . '>' . $category->name.'</a>';
echo $category->description . '</li>';
}
echo '</ul>';
}
