I am having a little trouble editing a Woocommerce template with hooks. Essentially I would just like to change the product-image template so instead of linking to the uploaded product image, it links to the product post.
The current product-image.php woocommerce template has
global $post, $woocommerce, $product;
?>
<div class="images">
<?php
if ( has_post_thumbnail() ) {
$image_title = esc_attr( get_the_title( get_post_thumbnail_id() ) );
$image_link = wp_get_attachment_url( get_post_thumbnail_id() );
$image = get_the_post_thumbnail( $post->ID, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ), array(
'title' => $image_title
) );
$attachment_count = count( $product->get_gallery_attachment_ids() );
if ( $attachment_count > 0 ) {
$gallery = '[product-gallery]';
} else {
$gallery = '';
}
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s', $image_link, $image_title, $image ), $post->ID );
} else {
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="Placeholder" />', woocommerce_placeholder_img_src() ), $post->ID );
}
?>
<?php do_action( 'woocommerce_product_thumbnails' ); ?>
</div>
I am unsure of how to adapt the echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s', $image_link, $image_title, $image ), $post->ID ); to change the %s to a link to the post.
The hook I am using is:
add_action('woocommerce_product_thumbnails', 'custom_links');
function custom_links() {
//code
}
Could someone help me gain some direction with this?
You are calling action not filter. Also you are calling the wrong one.
Change this:
add_action('woocommerce_product_thumbnails', 'custom_links');
to this:
add_filter('woocommerce_single_product_image_html', 'custom_links', 10, 2);
The 2 represents the argument count for the function and your custom_links() should be something like:
function custom_links($link, $post_id) {
$pattern = '/(?<=href=")([^"]*)/';
$replacement = get_permalink($post->ID);
return preg_replace($pattern, $replacement, $link);
}
Process the $link variable as needed and then return it.
Related
I am editing the latest-blog.php file for WordPress and I have two goals.
I would like the post category to be displayed and have a class of category assigned to it.
I would like to assign a class to the thumbnail, the title and the excerpt so I can style them.
The code below is where I believe the changes need to made
foreach ( $recent_posts as $post ) {
$post_id = $post['ID'];
$title = get_the_title( $post_id );
if ( ! $title ) {
$title = __( '(Untitled)' );
}
$post_url = get_permalink( $post_id );
$text = get_post( $post_id );
$text = $text->post_content;
$text = wp_trim_words( $text, 25, '... <a class="subtitle-red" style="display:block;" href="'.$post_url.'">read full article</a>' );
$excerpt = $text;
$list_items_markup .= sprintf(
'<li>
%1$s%3$s<p>%4$s</p>',
get_the_post_thumbnail( $post_id ),
esc_url( get_permalink( $post_id ) ),
esc_html( $title ),
$excerpt
);
if ( isset( $attributes['displayPostDate'] ) && $attributes['displayPostDate'] ) {
$list_items_markup .= sprintf(
'<time datetime="%1$s" class="wp-block-latest-posts__post-date">%2$s</time>',
esc_attr( get_the_date( 'c', $post_id ) ),
esc_html( get_the_date( '', $post_id ) )
);
}
$list_items_markup .= "</li>\n";
}
As this is a core WP file editing it really isn't the best idea so an extra question... could this be done via functions.php instead?
Thanks
TJ
I would like to change the dir path of my image. The current product-image.php woocommerce template is :
<?php
if( has_post_thumbnail() ) {
$image = get_the_post_thumbnail( $post->ID, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ) );
$image_title = esc_attr( get_the_title( get_post_thumbnail_id() ) );
$image_link = wp_get_attachment_url( get_post_thumbnail_id() );
list( $magnifier_url, $magnifier_width, $magnifier_height ) = wp_get_attachment_image_src( get_post_thumbnail_id(), "shop_magnifier" );
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s', $magnifier_url, $image_title, $image ), $post->ID );
} else {
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt=" ' . esc_attr__( 'Placeholder', 'jico' ) . ' " />', $placeholder, $placeholder ), $post->ID );
}
?>
How can i customize the %s in img src="%s" ?
Could someone help me gain some direction with this?
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' );
echo $image[0]
I want to replace full size image with large image on woocommerce lighbox.
here is my code -
<?php
if ( has_post_thumbnail() ) {
$image = get_the_post_thumbnail( $post->ID, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ) );
$image_title = esc_attr( get_the_title( get_post_thumbnail_id() ) );
$image_link = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID) );
$attachment_count = count( $product->get_gallery_attachment_ids() );
if ( $attachment_count > 0 ) {
$gallery = '[product-gallery]';
} else {
$gallery = '';
}
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s', $image_link, $image_title, $image ), $post->ID );
} else {
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="Placeholder" class="bigbox" />', woocommerce_placeholder_img_src() ), $post->ID );
}
?>
<?php do_action( 'woocommerce_product_thumbnails' ); ?>
I've tried to change $image_link to
$image_link = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), 'large' );
with no luck.
The $image_link comes as array. to echo the image link, try,
<?php echo $image_link[0]; ?>
So your full code should be like this
WooCommerce has the filter 'woocommerce_single_product_image_html' , you don't repeat the code in your theme for this.
You would add the following in your functions.php or your functions plugin.
Note: this works in 2.6x and will not work with 2.7 since they changed the single image display a lot.
function yourprefix_woocommerce_single_product_image_html( $html, $post_id ) {
if ( ! class_exists( 'WooCommerce' ) ) return;
//bail if WooCommerce is not installed and active since we are using the WC_VERSION constant
if ( version_compare( WC_VERSION, '2.7', '<' ) ) {
$image_title = esc_attr( get_the_title( get_post_thumbnail_id() ) );
$image_link = wp_get_attachment_image_src( get_post_thumbnail_id(), 'large' ); //this is where and use the [0] on this variable in the sprintf
$image = get_the_post_thumbnail( $post_id, 'shop_single', array( 'title' => $image_title ) );
$html = sprintf('%s', $image_link[0], $image_title, $image );
} //end version compare still return the html so we don't get an error
return $html;
}
add_filter( 'woocommerce_single_product_image_html', 'yourprefix_woocommerce_single_product_image_html', 10, 2 );
Note: wp_get_attachment_image_src() is not what is used in the default code, it's wp_get_attachment_image_url() which gets the image uploaded, not a sized image. If you want the generated image use $variable = wp_get_attachment_image_src( ... ); and then $variable[0] for the url, $variable[1] width, $variable[2] height. There are plenty of tuts on this, so I won't repeat
I am trying to display how many percent the user saves on the sales badge in WooCommerce. To make this work without this overwriting the "Featured" sales badge, I had to add some filters to my functions.php. Everything works fine now, exept that the product image on the product page disappears and I can't for the life of me understand why. The "onsale featured" code in the theme file product-image.php is almost the same as the "onsale" code, and I can't understand why the image would disappear when a product is on sale, but not when it is featured?
My code in functions.php
add_filter('woocommerce_sale_flash', 'my_custom_sale_flash' );
function my_custom_sale_flash($text) {
global $product;
if($product->is_on_sale()){
$percentage = round( ( ( $product->regular_price - $product->sale_price ) / $product->regular_price ) * 100 );
return '<span class="onsale">SPAR '.$percentage.' %</span>';
}elseif($product->is_featured()){
return '<span class="onsale featured">Utvalgt</span>';
}else if(!$product->is_in_stock()){
return '<span class="onsale">Utsolgt</span>';
}else if(!$product->get_price()){
return '<span class="onsale">GRATIS</span>';
}
}
The code in product-image.php in the ROEN theme
<?php
/**
* Single Product Image
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.0.14
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
global $post, $woocommerce, $product;
?>
<div class="images">
<?php
if ( has_post_thumbnail() ) {
$image_title = "";
$image_link = wp_get_attachment_url( get_post_thumbnail_id() );
$image = get_the_post_thumbnail( $post->ID, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ), array('title' => $image_title) );
$attachment_count = count( $product->get_gallery_attachment_ids() );
if ( $attachment_count > 0 ) {
$gallery = '[product-gallery]';
$zoom = "";
} else {
$gallery = '';
$zoom = 'zoom';
}
$html = '';
if($product->is_featured()){
$html = apply_filters('woocommerce_sale_flash', '<span class="featured onsale">'.__('Featured','ROEN').'</span>', $post, $product);
}else if($product->is_on_sale()){
$html = apply_filters('woocommerce_sale_flash', '<span class="onsale">'.__( 'Sale!', 'woocommerce' ).'</span>', $post, $product);
}else if(!$product->is_in_stock()){
$html = '<span class="outofstock">'.__('Out of Stock','ROEN').'</span>';
}else if(!$product->get_price()){
$html = '<span class="free onsale">'.__('Free','ROEN').'</span>';
}
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s'.$html.'', $image_link, $image_title, $image_link , $image ), $post->ID );
} else {
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="Placeholder" />', woocommerce_placeholder_img_src() ), $post->ID );
}
?>
<?php do_action( 'woocommerce_product_thumbnails' ); ?>
</div>
I can't see why the problem arises? Featured products that are not on sale displays correctly both when viewed from a category and on the product page. Products that are on sale displays correctly when viewed from a category, but the image disappears on the product page.
Thank you for your time.
I got this fixed by changing
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s'.$html.'', $image_link, $image_title, $image_link , $image ), $post->ID );
To
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s%s', $image_link, $image_title, $image_link , $image, $html ), $post->ID );
Turns out Wordpress did not like the percentage sign in my span that was going to show in the sales badge, because of the way the ROEN theme is coded.
I tell you man, lot's of weird code in that theme.
I'm building a Woocommerce site.
In the Shop grid overview, I'm showing the Featured Image of each product (see link). This Featured image will be cropped to maintain the same image ratio in the Shop Grid.
In the Single Product page, I managed to hide the Featured Image, and make the first of the thumbnails appear in big (see link).
I did so with the following code:
<div class="images">
<?php
$imgid = $product->get_gallery_attachment_ids();
?>
<a href="<?php echo wp_get_attachment_url( $imgid[0] ); ?>"
class="woocommerce-main-image zoom first"
rel="lightbox[product-gallery]">
<img src="<?php echo wp_get_attachment_url( $imgid[0] ); ?>" alt="">
</a>
<?php do_action( 'woocommerce_product_thumbnails' ); ?>
</div>
<script>
jQuery('.thumbnails.columns-3 a:first-child').hide()
</script>
The first part will find the first image in the gallery array and show it in big size (class woocommerce-main-image zoom first) while linking to the lightbox.
Then I call the thumbnails, and I hide the first one using jQuery to avoid a duplicate (first big size image and first thumb are the same).
The problem now is that in the Lightbox, the first image will appear duplicated, as it exists two times in the array, the first one I call in big, and the one from the thumbs array.
Any tips on how to not show the image twice in the lightbox?
Someone mentioned that I should filter the following function, but as of now I don't know how to do that.
public function get_gallery_attachment_ids() {
return apply_filters( 'woocommerce_product_gallery_attachment_ids', array_filter( (array) explode( ',', $this->product_image_gallery ) ), $this );
}
I think that using Multiple Post Thumbnails is the easiest solution. It is exactly for displaying different featured images in different locations.
Option #1: Multiple Post Thumbnails
You would install the plugin and then add the following to your theme's functions.php. It isn't 100% tested so there may be a stray typo or something. Full documentation is here.
// register the new thumbnail
function so_31835142_register_extra_thumbnail() {
if (class_exists('MultiPostThumbnails')) {
new MultiPostThumbnails(
array(
'label' => __('Product Loop Image', 'your-theme'),
'id' => 'product-loop-image',
'post_type' => 'product'
)
);
}
}
add_action( 'after_setup_theme', 'so_31835142_register_extra_thumbnail' );
// remove the existing loop thumbnail
function so_31835142_swap_loop_product_thumbnail(){
if (class_exists('MultiPostThumbnails')) {
remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
add_action( 'woocommerce_before_shop_loop_item_title', 'so_31835142_loop_product_thumbnail', 10 );
}
}
add_action( 'woocommerce_before_shop_loop_item, 'so_31835142_swap_loop_product_thumbnail' );
// Display the Secondary Thumbnail
function so_31835142_loop_product_thumbnail(){
global $product;
$thumbnail = MultiPostThumbnails::get_post_thumbnail(
'product',
'product-loop-image',
$product->id,
'shop_catalog'
);
if ( $thumbnail ) {
return $thumbnail;
} elseif ( wc_placeholder_img_src() ) {
return wc_placeholder_img( $size );
}
}
Then to use it, you'd set "Product Loop Image" the same way you traditionally set the "featured image". And this new image would be used in the loop.
Option #2: Template Overrides
But as an alternative, if you insist, you can write a custom single-product/product-image.php template and put it in your theme's woocommerce templates folder.
In this alternative we will only show images from the image gallery on the single product page, $product->get_gallery_attachment_ids(), and we will use a basic PHP loop and counter system to display the images differently depending on where they are in the loop. IE. the first image will display as the post thumbnail used to display and the remaining items will display as thumbs.
This section I have tested, so it should (in theory) be good to go.
<?php
/**
* Single Product Image
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.0.14
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $post, $woocommerce, $product;
?>
<div class="images">
<?php
$attachment_ids = $product->get_gallery_attachment_ids();
if ( $attachment_ids ) {
$loop = 0;
$columns = apply_filters( 'woocommerce_product_thumbnails_columns', 3 );
$attachment_count = count( $attachment_ids );
foreach ( $attachment_ids as $attachment_id ) {
// here's your first image
if( $loop === 0 ){
$image_title = esc_attr( get_the_title( $attachment_id ) );
$image_caption = get_post( $attachment_id )->post_excerpt;
$image_link = wp_get_attachment_url( $attachment_id );
$image = wp_get_attachment_image( $attachment_id, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ), null, array(
'title' => $image_title,
'alt' => $image_title
) );
if ( $attachment_count > 0 ) {
$gallery = '[product-gallery]';
} else {
$gallery = '';
}
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '%s', $image_link, $image_caption, $image ), $post->ID );
// resume the thumbnails for the rest
} else {
// open the thumbnails div
if( $loop === 1 ) { ?>
<div class="thumbnails <?php echo 'columns-' . $columns; ?>">
<?php }
$classes = array( 'zoom' );
if ( $loop == 0 || $loop % $columns == 0 )
$classes[] = 'first';
if ( ( $loop + 1 ) % $columns == 0 )
$classes[] = 'last';
$image_link = wp_get_attachment_url( $attachment_id );
if ( ! $image_link )
continue;
$image_title = esc_attr( get_the_title( $attachment_id ) );
$image_caption = esc_attr( get_post_field( 'post_excerpt', $attachment_id ) );
$image = wp_get_attachment_image( $attachment_id, apply_filters( 'single_product_small_thumbnail_size', 'shop_thumbnail' ), 0, $attr = array(
'title' => $image_title,
'alt' => $image_title
) );
$image_class = esc_attr( implode( ' ', $classes ) );
echo apply_filters( 'woocommerce_single_product_image_thumbnail_html', sprintf( '%s', $image_link, $image_class, $image_caption, $image ), $attachment_id, $post->ID, $image_class );
// close the thumbnails div
if( $loop === $attachment_count ) { ?>
</div>
<?php }
}
$loop++;
}
?>
<?php
} else {
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="%s" />', wc_placeholder_img_src(), __( 'Placeholder', 'woocommerce' ) ), $post->ID );
}
?>
</div>