I am using the Origin theme for wordpress and I am trying to customize the comments link right above the post. Right now it shows the number of comments and the text "comment" but I would like to only show the number (and show 0 when there are no comments). I found the relevant code in the theme > library > functions folder in shortcodes.php.
How do I edit this to only show the number of comments without the "comments" text for eg. "1" instead of "1 comment"?
This is the code currently:
function hybrid_entry_comments_link_shortcode( $attr ) {
$comments_link = '';
$number = doubleval( get_comments_number() );
$attr = shortcode_atts( array( 'zero' => __( 'Leave a comment', 'hybrid-core' ), 'one' => __( '%1$s comment', 'hybrid-core' ), 'more' => __( '%1$s comments', 'hybrid-core' ), 'css_class' => 'comments-link', 'none' => '', 'before' => '', 'after' => '' ), $attr );
if ( 0 == $number && !comments_open() && !pings_open() ) {
if ( $attr['none'] )
$comments_link = '<span class="' . esc_attr( $attr['css_class'] ) . '">' . sprintf( $attr['none'], number_format_i18n( $number ) ) . '</span>';
}
elseif ( 0 == $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_permalink() . '#respond" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['zero'], number_format_i18n( $number ) ) . '</a>';
elseif ( 1 == $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_comments_link() . '" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['one'], number_format_i18n( $number ) ) . '</a>';
elseif ( 1 < $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_comments_link() . '" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['more'], number_format_i18n( $number ) ) . '</a>';
if ( $comments_link )
$comments_link = $attr['before'] . $comments_link . $attr['after'];
return $comments_link;
}
You just need to remove the word "comment" or "comments" in the relevant bits.
The line in question begins with $attr = shortcode_atts( ....
Here it is modified for you:
function hybrid_entry_comments_link_shortcode( $attr ) {
$comments_link = '';
$number = doubleval( get_comments_number() );
$attr = shortcode_atts( array( 'zero' => __( 'Leave a comment', 'hybrid-core' ), 'one' => __( '%1$s', 'hybrid-core' ), 'more' => __( '%1$s', 'hybrid-core' ), 'css_class' => 'comments-link', 'none' => '', 'before' => '', 'after' => '' ), $attr );
if ( 0 == $number && !comments_open() && !pings_open() ) {
if ( $attr['none'] )
$comments_link = '<span class="' . esc_attr( $attr['css_class'] ) . '">' . sprintf( $attr['none'], number_format_i18n( $number ) ) . '</span>';
}
elseif ( 0 == $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_permalink() . '#respond" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['zero'], number_format_i18n( $number ) ) . '</a>';
elseif ( 1 == $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_comments_link() . '" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['one'], number_format_i18n( $number ) ) . '</a>';
elseif ( 1 < $number )
$comments_link = '<a class="' . esc_attr( $attr['css_class'] ) . '" href="' . get_comments_link() . '" title="' . sprintf( esc_attr__( 'Comment on %1$s', 'hybrid-core' ), the_title_attribute( 'echo=0' ) ) . '">' . sprintf( $attr['more'], number_format_i18n( $number ) ) . '</a>';
if ( $comments_link )
$comments_link = $attr['before'] . $comments_link . $attr['after'];
return $comments_link;
}
Related
I'm using a code to initial a select2 field in WooCommerce Backend. The selecting field is working good, but I have problems after saving product.
I cannot get the value from db and be pre-selected. Also can not save it as well.
Can anybody give a tip with this? Should data be saved as an array?
My code:
function woocommerce_wp_product_select2( $field ) {
global $thepostid, $post, $woocommerce;
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
$field['class'] = isset( $field['class'] ) ? $field['class'] : 'select short';
$field['wrapper_class'] = isset( $field['wrapper_class'] ) ? $field['wrapper_class'] : '';
$field['name'] = isset( $field['name'] ) ? $field['name'] : $field['id'];
echo '<p class="form-field ' . esc_attr( $field['id'] ) . '_field ' . esc_attr( $field['wrapper_class'] ) . '"><label for="' . esc_attr( $field['id'] ) . '">' . wp_kses_post( $field['label'] ) . '</label><select id="' . esc_attr( $field['id'] ) . '" name="' . esc_attr( $field['name'] ) . '" class="wc-product-search ' . esc_attr( $field['class'] ) . '" multiple="multiple" data-maximum-selection-length="1">';
foreach ( $field['value'][0] as $key => $value ) {
echo '<option value="'.$value.'" selected="selected">'.wc_get_product( $value )->name.' (#'.$value.')</option>';
}
echo '</select> ';
if ( ! empty( $field['description'] ) ) {
if ( isset( $field['desc_tip'] ) && false !== $field['desc_tip'] ) {
echo '<span class="woocommerce-help-tip" data-tip="' . esc_attr( $field['description'] ) . '"></span>';
} else {
echo '<span class="description">' . wp_kses_post( $field['description'] ) . '</span>';
}
}
echo '</p>';
}
add_filter( 'woocommerce_product_data_tabs', 'kyatipov_promo_tab', 10, 1 );
function kyatipov_promo_tab($default_tabs) {
$default_tabs['promo'] = array(
'label' => __( 'Промоция', 'domain' ),
'target' => 'kyatipov_promo_tab_content',
'priority' => 60,
'class' => array('promo-tab-produkti')
);
return $default_tabs;
}
add_action( 'woocommerce_product_data_panels', 'kyatipov_promo_tab_content' );
function kyatipov_promo_tab_content() {
global $woocommerce, $post;
?>
<div id="kyatipov_promo_tab_content" class="panel woocommerce_options_panel">
<style>
#woocommerce-product-data ul li.promo_options.promo_tab.promo-tab-produkti a::before {
font-family: Dashicons;
content: "\f198";
}
h4#ízbran-produkt, h4#iztrii-izbran-prod {
margin-left: 12px;
}
.iztrii-container {
display: flex;
}
h4#iztrii-izbran-prod::after {
font-family: Dashicons;
content: "\f182";
color: red;
font-size: 26px;
}
h4#iztrii-izbran-prod {
margin-top: 0;
}
h4#iztrii-izbran-prod:hover {
cursor: -webkit-grabbing; cursor: grabbing;
}
select#wc_product_ids + span.select2 {
width: 350px !IMPORTANT;
}
</style>
<?php
woocommerce_wp_checkbox( array(
'id' => '_enable_promo_for_current_product',
//'wrapper_class' => 'show_if_simple',
'label' => __( 'Включи промо', 'woocommerce' ),
'description' => __( 'Тази опция е задължителна, ако желаете да ползвате промо фу-ота за този продукт!', 'my_text_domain' ),
'default' => '0',
'desc_tip' => true,
) );
$save_data = get_post_meta( $post->ID, 'wc_product_ids' );
echo $save_data;
print_r($save_data);
woocommerce_wp_product_select2([
'id' => 'wc_product_ids',
'label' => __( 'Продукт', 'woocommerce' ),
'class' => '',
'name' => 'wc_product_ids[]',
'value' => $save_data,
'desc_tip' => true,
'description' => __( 'Избери продукт за промоция', 'wc' ),
]);
echo '</div>';
}
// Save Meta
add_action('woocommerce_process_product_meta', 'kyatipov_custom_field_save');
function kyatipov_custom_field_save( $post_id ){
// Select
$izbran_promo_prod = $_POST['wc_product_ids'];
if( !empty( $izbran_promo_prod ) )
update_post_meta( $post_id, 'wc_product_ids', esc_attr( $izbran_promo_prod ) );
$izbran_promo_prod2 = $_POST['save_data'];
if( !empty( $izbran_promo_prod2 ) )
update_post_meta( $post_id, 'save_data', esc_attr( $izbran_promo_prod2 ) );
}
First of all I modified the woocommerce_wp_product_select2() function you are using:
I've added $field['placeholder'] to the function, so that a placeholder can be used if desired
data-exclude="<?php echo $thepostid; ?>" has been added so that the current product cannot be selected
$field['value'] = ! empty( $field['value'] ) ? $field['value'] : array(); was also added to the function, to avoid an error message when the metadata does not exist/do not yet exist
When it comes to saving, you're making the mistake that esc_attr() is used with an array, while it expects a string
p.s. to save fields you can use the woocommerce_admin_process_product_object hook, opposite the outdated woocommerce_process_product_meta hook
So you get:
function woocommerce_wp_product_select2( $field ) {
global $thepostid, $post;
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
$field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
$field['class'] = isset( $field['class'] ) ? $field['class'] : 'select short';
$field['wrapper_class'] = isset( $field['wrapper_class'] ) ? $field['wrapper_class'] : '';
$field['value'] = ! empty( $field['value'] ) ? $field['value'] : array();
$field['name'] = isset( $field['name'] ) ? $field['name'] : $field['id'];
echo '<p class="form-field ' . esc_attr( $field['id'] ) . '_field ' . esc_attr( $field['wrapper_class'] ) . '"><label for="' . esc_attr( $field['id'] ) . '">' . wp_kses_post( $field['label'] ) . '</label><select id="' . esc_attr( $field['id'] ) . '" name="' . esc_attr( $field['name'] ) . '" class="wc-product-search ' . esc_attr( $field['class'] ) . '" multiple="multiple" style="width: 50%;" data-maximum-selection-length="1" data-placeholder="' . esc_attr( $field['placeholder'] ) . '" data-exclude="<?php echo $thepostid; ?>" >';
foreach ( $field['value'] as $key => $value ) {
$product = wc_get_product( $value );
if ( is_object( $product ) ) {
echo '<option value="' . esc_attr( $value ) . '"' . selected( true, true, false ) . '>' . esc_html( wp_strip_all_tags( $product->get_formatted_name() ) ) . '</option>';
}
}
echo '</select> ';
if ( ! empty( $field['description'] ) ) {
if ( isset( $field['desc_tip'] ) && false !== $field['desc_tip'] ) {
echo '<span class="woocommerce-help-tip" data-tip="' . esc_attr( $field['description'] ) . '"></span>';
} else {
echo '<span class="description">' . wp_kses_post( $field['description'] ) . '</span>';
}
}
echo '</p>';
}
function filter_woocommerce_product_data_tabs( $default_tabs ) {
$default_tabs['promo'] = array(
'label' => __( 'Промоция', 'domain' ),
'target' => 'kyatipov_promo_tab_content',
'priority' => 60,
'class' => array( 'promo-tab-produkti' )
);
return $default_tabs;
}
add_filter( 'woocommerce_product_data_tabs', 'filter_woocommerce_product_data_tabs', 10, 1 );
function action_woocommerce_product_data_panels() {
global $post;
echo '<div id="kyatipov_promo_tab_content" class="panel woocommerce_options_panel">';
// Get data
$data = get_post_meta( $post->ID, '_wc_product_ids', true );
// Add field via custom function
woocommerce_wp_product_select2(
array(
'id' => 'wc_product_ids',
'label' => __( 'Продукт', 'woocommerce' ),
'placeholder' => __( 'My placeholder', 'woocommerce' ),
'class' => '',
'name' => 'wc_product_ids[]',
'value' => $data,
'desc_tip' => true,
'description' => __( 'Избери продукт за промоция', 'woocommerce' ),
)
);
echo '</div>';
}
add_action( 'woocommerce_product_data_panels', 'action_woocommerce_product_data_panels' );
// Save
function action_woocommerce_admin_process_product_object( $product ) {
// Good idea to make sure things are set before using them
$data = isset( $_POST['wc_product_ids'] ) ? (array) $_POST['wc_product_ids'] : array();
// Update
$product->update_meta_data( '_wc_product_ids', array_map( 'esc_attr', $data ) );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
Related: Add custom select2 search field into WooCommerce product data metabox
On my woocommerce site I added the woocommerce price filter in the sidebar of the store. The problem is that the price is placed next to the Filter button and then the text wraps. How can I move the text above the button? Do I have to change the php code of the price filter?
I inspected the page with google chrome and I saw that moving a div further up I solved the problem, but how do I apply it?
look at the sidebar link
this is the php file
class WC_Widget_Price_Filter extends WC_Widget {
/**
* Constructor.
*/
public function __construct() {
$this->widget_cssclass = 'woocommerce widget_price_filter';
$this->widget_description = __( 'Display a slider to filter products in your store by price.', 'woocommerce' );
$this->widget_id = 'woocommerce_price_filter';
$this->widget_name = __( 'Filter Products by Price', 'woocommerce' );
$this->settings = array(
'title' => array(
'type' => 'text',
'std' => __( 'Filter by price', 'woocommerce' ),
'label' => __( 'Title', 'woocommerce' ),
),
);
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2' );
wp_register_script( 'wc-jquery-ui-touchpunch', WC()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch' . $suffix . '.js', array( 'jquery-ui-slider' ), WC_VERSION, true );
wp_register_script( 'wc-price-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider', 'wc-jquery-ui-touchpunch', 'accounting' ), WC_VERSION, true );
wp_localize_script( 'wc-price-slider', 'woocommerce_price_slider_params', array(
'currency_format_num_decimals' => 0,
'currency_format_symbol' => get_woocommerce_currency_symbol(),
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ),
) );
if ( is_customize_preview() ) {
wp_enqueue_script( 'wc-price-slider' );
}
parent::__construct();
}
/**
* Output widget.
*
* #see WP_Widget
*
* #param array $args
* #param array $instance
*/
public function widget( $args, $instance ) {
global $wp;
if ( ! is_shop() && ! is_product_taxonomy() ) {
return;
}
if ( ! wc()->query->get_main_query()->post_count ) {
return;
}
wp_enqueue_script( 'wc-price-slider' );
// Find min and max price in current result set.
$prices = $this->get_filtered_price();
$min = floor( $prices->min_price );
$max = ceil( $prices->max_price );
if ( $min === $max ) {
return;
}
$this->widget_start( $args, $instance );
if ( '' === get_option( 'permalink_structure' ) ) {
$form_action = remove_query_arg( array( 'page', 'paged', 'product-page' ), add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
} else {
$form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
}
$min_price = isset( $_GET['min_price'] ) ? esc_attr( $_GET['min_price'] ) : apply_filters( 'woocommerce_price_filter_widget_min_amount', $min );
$max_price = isset( $_GET['max_price'] ) ? esc_attr( $_GET['max_price'] ) : apply_filters( 'woocommerce_price_filter_widget_max_amount', $max );
echo '<form method="get" action="' . esc_url( $form_action ) . '">
<div class="price_slider_wrapper">
<div class="price_slider" style="display:none;"></div>
<div class="price_slider_amount">
<input type="text" id="min_price" name="min_price" value="' . esc_attr( $min_price ) . '" data-min="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_min_amount', $min ) ) . '" placeholder="' . esc_attr__( 'Min price', 'woocommerce' ) . '" />
<input type="text" id="max_price" name="max_price" value="' . esc_attr( $max_price ) . '" data-max="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_max_amount', $max ) ) . '" placeholder="' . esc_attr__( 'Max price', 'woocommerce' ) . '" />
<button type="submit" class="button">' . esc_html__( 'Filter', 'woocommerce' ) . '</button>
<div class="price_label" style="display:none;">
' . esc_html__( 'Price:', 'woocommerce' ) . ' <span class="from"></span> — <span class="to"></span>
</div>
' . wc_query_string_form_fields( null, array( 'min_price', 'max_price' ), '', true ) . '
<div class="clear"></div>
</div>
</div>
</form>';
$this->widget_end( $args );
}
/**
* Get filtered min price for current products.
* #return int
*/
protected function get_filtered_price() {
global $wpdb;
$args = wc()->query->get_main_query()->query_vars;
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
if ( ! is_post_type_archive( 'product' ) && ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
$tax_query[] = array(
'taxonomy' => $args['taxonomy'],
'terms' => array( $args['term'] ),
'field' => 'slug',
);
}
foreach ( $meta_query + $tax_query as $key => $query ) {
if ( ! empty( $query['price_filter'] ) || ! empty( $query['rating_filter'] ) ) {
unset( $meta_query[ $key ] );
}
}
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$sql = "SELECT min( FLOOR( price_meta.meta_value ) ) as min_price, max( CEILING( price_meta.meta_value ) ) as max_price FROM {$wpdb->posts} ";
$sql .= " LEFT JOIN {$wpdb->postmeta} as price_meta ON {$wpdb->posts}.ID = price_meta.post_id " . $tax_query_sql['join'] . $meta_query_sql['join'];
$sql .= " WHERE {$wpdb->posts}.post_type IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_post_type', array( 'product' ) ) ) ) . "')
AND {$wpdb->posts}.post_status = 'publish'
AND price_meta.meta_key IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_meta_keys', array( '_price' ) ) ) ) . "')
AND price_meta.meta_value > '' ";
$sql .= $tax_query_sql['where'] . $meta_query_sql['where'];
if ( $search = WC_Query::get_main_search_query_sql() ) {
$sql .= ' AND ' . $search;
}
return $wpdb->get_row( $sql );
}
Replace the form code (widget function -> below $max_price variable) with this:
echo '<form method="get" action="' . esc_url( $form_action ) . '">
<div class="price_slider_wrapper">
<div class="price_slider" style="display:none;"></div>
<div class="price_slider_amount">
<input type="text" id="min_price" name="min_price" value="' . esc_attr( $min_price ) . '" data-min="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_min_amount', $min ) ) . '" placeholder="' . esc_attr__( 'Min price', 'woocommerce' ) . '" />
<input type="text" id="max_price" name="max_price" value="' . esc_attr( $max_price ) . '" data-max="' . esc_attr( apply_filters( 'woocommerce_price_filter_widget_max_amount', $max ) ) . '" placeholder="' . esc_attr__( 'Max price', 'woocommerce' ) . '" />
<div class="price_label" style="display:none;">
' . esc_html__( 'Price:', 'woocommerce' ) . ' <span class="from"></span> — <span class="to"></span>
</div>
' . wc_query_string_form_fields( null, array( 'min_price', 'max_price' ), '', true ) . '
<button type="submit" class="button">' . esc_html__( 'Filter', 'woocommerce' ) . '</button>
<div class="clear"></div>
</div>
</div>
</form>';
i try to write a simple code for php, which can show date,post autho and category but i can not show category. Where can i add it? this is code:
$posted_on = sprintf(
esc_html_x( 'Posted on111 %s', 'post date', 'sanse' ),
'' . $time_string . ''
);
$byline = sprintf(
esc_html_x( 'by %s', 'post author', 'sanse' ),
'<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
);
Inside have_posts loop you can use get_the_category() function to display posts' categories.
$categories = get_the_category();
if ( ! empty( $categories ) ) {
echo '' . esc_html( $categories[0]->name ) . '';
}
https://developer.wordpress.org/reference/functions/get_the_category/
add_filter( 'woocommerce_form_field_args', 'custom_form_field_args', 10, 3 );
function custom_form_field_args( $args, $key, $value ) {
if ( $args['id'] == 'billing_city' ) {
$args = array(
'label' => __( 'Town / City', 'woocommerce' ),
'required' => TRUE,
'clear' => TRUE,
'type' => 'select',
'options' => array(
'' => ('Select City' ),
'Duliajan' => ('Duliajan' )
),
'class' => array( 'update_totals_on_change' )
);
} // elseif … and go on
return $args;
};
When I add the piece of code for a single city in (woocommerce) function.php, I got the following error.
Line number 2040-- $field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' data-placeholder="' . esc_attr( $args['placeholder'] ) . '">
Line no 2064-- $field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>';
How can I solve the error?
$args['input_class'] and $args['label_class'] must be arrays so they are probably not. Your should check:
if (!is_array($args['label_class']) {
// initialize to some empty array? depends on your application, what it needs to do
}
I am able to list the taxonomy children:
<?php
$taxonomy = 'store_name';
$tax_terms = get_terms($taxonomy);
?>
<ul class="split-list2">
<?php
foreach ($tax_terms as $tax_term) {
echo '<li>' . '<a href="' . esc_attr(get_term_link($tax_term, $taxonomy)) . '" title="' . sprintf( __( "View all posts in %s" ), $tax_term->name ) . '" ' . '>' . $tax_term->name.'</a></li>';
}
</ul> ?>
And I found a plugin to make thumbnails for categories/taxonomies:
https://wordpress.org/plugins/taxonomy-images/
But I can't figure out how to add the code to include the thumbnails to the taxonomy category grids.
Does anyone know how to do this
Read the plugin doc perfactly it gives what you want
print apply_filters( 'taxonomy-images-list-the-terms', '', array(
'after' => '</div>',
'after_image' => '</span>',
'before' => '<div class="my-custom-class-name">',
'before_image' => '<span>',
'image_size' => 'detail',
'post_id' => 1234,
'taxonomy' => 'post_tag',
) );
Second parameter in apply_filters( 'taxonomy-images-get-terms', '' ); is array as show above
$terms = apply_filters( 'taxonomy-images-get-terms', '' );
if ( ! empty( $terms ) ) {
print '<ul>';
foreach( (array) $terms as $term ) {
print '<li><a href="' . esc_url( get_term_link( $term, $term->taxonomy ) ) . '">' . wp_get_attachment_image( $term->image_id, 'detail' ) . '</li>';
}
print '</ul>';
}