Automatically print WooCommerce orders

December 27th, 2018 Leave a comment Go to comments

Disclaimer: this doesn't have an easy solution, and the solutions that do exist are printer-specific, so we're not releasing this as a plugin.  It will almost certainly need to be modified to fit your specifications.

There are few, but not non-existent, situations in which it may be helpful to print a physical order summary on actual paper for your staff to fill.  This is one way to do it.  Once again, this will NOT work out of the proverbial box; you need to read and understand the code, and modify it to fit your needs.
<?php
/*
Plugin Name: WooCommerce Print Orders
Description: Hopefully this will print the orders at the printer in the office.
Author: Mango
Version: 0.1Alpha
*/
 
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
add_action('woocommerce_order_status_completed', 'wcpo_create', 10, 1);
 
// I'm going to put the variables up here, but there's no GUI for this.  If you're smart enough to use it, you're smart enough to configure here.
$GLOBALS['wcpo_config'] = array(
 'office_ip' => "toshiba.office",
 'office_port' => "9100",
 'error_email' => "webmaster@example.com",
 );
 
// Note that some web server firewalls do not allow outbound connections on port 9100.  One way to get around this is to, use your router to forward some allowed port such as 443 to your printer on port 9100.  When using port forwarding, be sure to restrict source IP appropriately so that random people cannot print to your printer.
 
// Menu item for this.
if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
 add_action('admin_menu', 'wcpo_menu');
 }
function wcpo_menu() {
 add_submenu_page('woocommerce', 'Print Orders', 'Print Orders', 'manage_options', 'wc-print-orders', 'wcpo_init');
 }
 
// Basic UI to enter an order ID and have it print; useful if the internet at the office is down and we need to catch up.
function wcpo_init(){
 echo "<p>Enter the Order ID to print an order</p>";
 echo "<form method='get' action=''><input name='order_id' /><input type='hidden' name='page' value='wc-print-orders' /><input type='submit' /></form>";
 if (isset($_GET['order_id'])) wcpo_create($_GET['order_id']); 
 }
 
// This is where the magic happens
function wcpo_create($order_id) {
 // First let us load the order, the ID of which is passed as the first parameter of this function.
 $order = new WC_Order($order_id);
 $order_data = $order->get_data();
 if ($order_data['status'] != "completed") return false; // This should never fire, but is here as a failsafe in case something goes horribly wrong..
 // Generate an order summary in HTML format.
 $html = ""
  . "<h2>New Online Order received on " . $order_data['date_completed']->date("F j \a\\t g:i a") . "</h2>"
  . "<p>{$order_data['billing']['first_name']} {$order_data['billing']['last_name']}<br />{$order_data['billing']['company']}</p>"
  . "<p>Phone: {$order_data['billing']['phone']}</p>"
  . "<h3>Items purchased:</h3><p>"
  ;
 // Loop through the items so we can include them in the order summary.
 $order_items = $order->get_items();
 foreach ($order_items as $item) $html .= "<b>{$item['quantity']}</b> of {$item['name']}<br />"; 
 $html .= "</p>";
 // Order notes.
 $html .= "<p>" . htmlspecialchars($order_data['customer_note']) . "</p>";
 // Now let's generate a PDF.  I decided to use TCPDF; you can use the library of your choice.  Since our printer can print PDFs, this is a reasonable choice.  Alternately, use pdf2ps to convert your 
 require_once('tcpdf/tcpdf.php');
 $pdf = new TCPDF('P', 'mm', 'LETTER');
 $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
 $pdf->SetFont('Helvetica', '', 14, '', true);
 $pdf->AddPage();
 $pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
 // The following are custom PJL commands that cause our printer to use input tray 3 and output tray 2.  If your printer doesn't support PJL commands, and the default settings don't work for you, there are other ways to do this.  Perhaps default settings for port 9100 may be set from within your printer's configuration.  Or if your printer supports PostScript, perhaps you can find a PPD file that gives you the PostScript commands to use.
 $pdf = ""
  . chr(27) . "%-12345X@PJL\r\n"
  . "@PJL SET TRAY=TRAY3\r\n"
  . "@PJL SET OUTBIN=FINISHERSHIFT\r\n"
  . "@PJL SET USERID = \"Mango\"\r\n"
  . "@PJL ENTER LANGUAGE = PDF\r\n"
  . $pdf->Output("", 'S')
  . chr(27) . "%-12345X"
  ;
 // Print it!
 $socket = @fsockopen($GLOBALS['wcpo_config']['office_ip'], $GLOBALS['wcpo_config']['office_port'], $errno, $errstr, 30);
 if (!$socket) return wcpo_error("Order $order_id\n\nCould not open the socket to {$GLOBALS['wcpo_config']['office_ip']}:{$GLOBALS['wcpo_config']['office_port']}.\n\n$errstr ($errno)");
 $written = fwrite($socket, $pdf); // doesn't work with very large files but IDGAF for this.
 fclose($socket);
 if ($written != strlen($pdf)) return wcpo_error("Order $order_id\n\nOnly $written of " . strlen($pdf) . " bytes were able to be sent to the printer.");
 }
 
function wcpo_error($e) {
 mail($GLOBALS['wcpo_config']['error_email'], "WooCommerce Print Order Summary: Error", $e, "From: {$GLOBALS['wcpo_config']['error_email']}");
 }

 

If you would like a reply to your comment, you must leave your email address! We receive dozens of questions every month from people who don't leave us with any way to contact them, so we have no choice but to ignore the question. We try to reply to as many questions as we can, if we know the email address of the person who asked the question. Thanks in advance for writing in :)

Allowed HTML: <b>, <i>, <em>, <strong>. All other < and > will be replaced with &lt; and &gt;.