phpwordpresswoocommerceproductorders

Change add to cart button text + url to My account Order view page when customer has previously bought the product


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?


Solution

  • 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;
    }
    

    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