The idea is to change the add to cart button text + url on WooCommerce shop and archives pages and the single product page.
The add to cart url should point to the view order detail page if the customer has previously bought the product.
Based on Custom add to cart button, if the customer has bought previously the product answer code, I was able to write the following code:
add_filter( 'woocommerce_loop_add_to_cart_link', 'customizing_add_to_cart_button', 10, 2 );
function customizing_add_to_cart_button( $link, $product ){
$bought = false;
if( is_user_logged_in() ){
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
// Going through each current customer orders
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order->ID );
// Going through each current customer order items
foreach($order->get_items() as $item_id => $item_values){
if($item_values['product_id'] == $product->id){
$bought = true;
break;
}
}
}
}
if($bought){
// ==> SET HERE YOUR
// CUSTOM ADD TO CART text and link
$add_to_cart_url = site_url('//*custom_link here i want set to open view order in my account/view order/{order_id} of bought product button view order now*/ /');
$button_text = __('View order now', 'woocommerce');
}
// for the product ID 45 (for example)
if( $product->id == 45 ){
$add_to_cart_url = site_url('/custom-link/product-45/');
$button_text = __('View now product 45', 'woocommerce');
}
else {
$add_to_cart_url = $product->add_to_cart_url();
$button_text = $product->add_to_cart_text();
}
$link = sprintf( '<a href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" data-quantity="%s" class="button product_type_%s">%s</a>',
esc_url( $add_to_cart_url ),
esc_attr( $product->id ),
esc_attr( $product->get_sku() ),
esc_attr( isset( $quantity ) ? $quantity : 1 ),
esc_attr( $product->product_type ),
esc_html( $button_text )
);
return $link;
}
What currently works:
What I need help with:
I took help from WooCommerce account endpoint - view order, but I didn't figured out how to write. Any advice?
To get the url from the My account Order view page you could use the get_view_order_url() function. However, since you then need access to the $order
object I wrote a custom function that gets the order ID by the product ID
function get_order_id_by_product_id( $product_id ) {
global $wpdb;
// Get user ID
$user_id = get_current_user_id();
// Get order ID by product ID
$order_id = $wpdb->get_var( "
SELECT p.ID FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
INNER JOIN {$wpdb->prefix}woocommerce_order_items AS woi ON p.ID = woi.order_id
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim ON woi.order_item_id = woim.order_item_id
WHERE p.post_status IN ( 'wc-completed' )
AND pm.meta_key = '_customer_user'
AND pm.meta_value = '$user_id'
AND woim.meta_key IN ( '_product_id', '_variation_id' )
AND woim.meta_value = '$product_id'
LIMIT 1
" );
// Return
return $order_id;
}
LIMIT 1
wc-completed
On WooCommerce shop and archives pages you can use the woocommerce_loop_add_to_cart_link
filter hoook. This allows you to rewrite the output of the add to cart button based on certain conditions. Once we know the order ID via the custom function, we will create our url
which will refer to the My account Order view page
// On WooCommerce shop and archives pages
function filter_woocommerce_loop_add_to_cart_link( $sprintf, $product, $args ) {
// Only for logged in users
if ( ! is_user_logged_in() ) return $sprintf;
// Only for single type products
if ( ! $product->is_type( 'simple' ) ) return $sprintf;
// Call fuction and get order ID
$order_id = get_order_id_by_product_id( $product->get_id() );
// When NOT empty
if ( ! empty( $order_id ) ) {
// Setting
$button_text_view_order = __( 'View order now', 'woocommerce' );
// Get view order url
$view_order_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
// New link + text
$sprintf = sprintf(
'<a href="%s" class="%s">%s</a>',
esc_url( $view_order_url ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
esc_html( $button_text_view_order )
);
}
return $sprintf;
}
add_filter( 'woocommerce_loop_add_to_cart_link', 'filter_woocommerce_loop_add_to_cart_link', 10, 3 );
For the single product page, an overwrite of the template file would actually be necessary, since the add to cart button does not immediately contain a specific hook to overwrite it.
However, we can replace the default button with our own custom button via a workaround
// On single product page, replacing the single add to cart product button by a custom button
function action_woocommerce_single_product_summary() {
global $product;
// Only for logged in users
if ( ! is_user_logged_in() ) return;
// Only for single type products
if ( ! $product->is_type( 'simple' ) ) return;
// Call fuction and get order ID
$order_id = get_order_id_by_product_id( $product->get_id() );
// When NOT empty
if ( ! empty( $order_id ) ) {
// Remove default add to cart button and add a custom one
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
// Add action, priority 30 and pass data to add action function
add_action( 'woocommerce_single_product_summary', function() use ( $order_id ) {
// Setting
$button_text_view_order = __( 'View order now', 'woocommerce' );
// Get view order url
$view_order_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
echo '<a href="' . $view_order_url . '" class="single_add_to_cart_button button alt">' . $button_text_view_order . '</a>';
}, 30, 0 );
}
}
add_action( 'woocommerce_single_product_summary', 'action_woocommerce_single_product_summary', 1 );
This code works for products of type 'single' but can be further expanded to meet your needs