Search code examples
phpwordpressobjectwoocommercehook-woocommerce

woocommerce_email_attachments hook with empty $order argument in Woocommerce


The person building a WP site for me is stuck for some time now with this problem. He needs to attach some custom PDF files into the order confirmation mail. He uses woocommerce_emails_attach_downloadables function to do that. For some reason that function is getting called with the $order parameter being empty.

Here is the code he uses :

add_filter( 'woocommerce_email_attachments', 'attach_order_notice', 10, 3 );
function attach_order_notice ( $attachments, $email_id, $order )
{

//

   // Only for "New Order" email notification (for admin)
   if( $email_id == 'customer_on_hold_order' ){

      $pdf_options = array(
//       "source_type" => 'html',
//       "source" => '<html>hello</html>',
         "source_type" => 'url',
         "source" => 'http://tt.dev.co.il/checkout/order-received/757/?key=wc_order_5bce0e5ba39b8',
         "action" => 'save',
         "save_directory" => get_template_directory() .'/pdfs',
         "file_name" => 'print-pdf'. json_encode($order) .'.pdf');


//    phptopdf($pdf_options);




      $attachments[] = get_template_directory() . '/pdfs/print-pdf.pdf';
   }
   return $attachments;
}

So my questions are:
What are those cases ?
What can cause $order to be passed as empty ?


Solution

  • Your developer has been using maybe this woocommerce official snippet (That is outdated as it is 3 years old) and it uses woocommerce_email_attachments filter hook.

    This filter hook is defined:

    • one time (1) in WC_Email class (with the $order argument)
    • three times (3) in WC_emails Class (without the $order argument)

    So the WC_Order Object $order is only defined in WC_Email class as third argument.

    That means that this outdated official code need to be tweaked as follow:

    add_filter( 'woocommerce_email_attachments', 'woocommerce_emails_attach_downloadables', 10, 3 );
    function woocommerce_emails_attach_downloadables( $attachments, $email_id, $order ) {
        // Avoiding errors and problems
        if ( ! is_a( $order, 'WC_Order' ) || ! isset( $email_id ) ) {
            return $attachments;
        }
    
        // ===>  Your custom code goes Here  <===
    
        return $attachments;
    }
    

    This should work avoiding problems.

    So as you are asking, this hook is also used on the following specific product notifications with really different hook arguments:

    • On "Low stock" notification (with 'low_stock' and $product as 2nd & 3rd arguments)
    • On "No stock" notification (with 'no_stock' and $product as 2nd & 3rd arguments)
    • On "Backorder" notification (with 'backorder' and $args as 2nd & 3rd arguments)

    So here the 2nd argument is the stock status $stock_status and the 3rd argument is the WC_Product object $product (or an array $args).

    Then In those 3 notifications, the $order object doesn't exist as it can be a WC_Product Object, an array, an empty array, or null.