WooCommerce PDF Invoices & Packing Slips - Version 1.5.28

Version Description

  • Tweak: the 'Next invoice number' is now stored separately in the database for faster and more reliable retrieval. Circumventing any caching, this should prevent duplicate invoice numbers.
  • Fix: Bulk actions plugin conflicts
  • Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
Download this release

Release Info

Developer pomegranate
Plugin Icon 128x128 WooCommerce PDF Invoices & Packing Slips
Version 1.5.28
Comparing to
See all releases

Code changes from version 1.5.27 to 1.5.28

includes/class-wcpdf-export.php CHANGED
@@ -47,6 +47,10 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
47
  require_once( $this->template_path . '/template-functions.php' );
48
  }
49
 
 
 
 
 
50
  add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ));
51
  add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3);
52
  add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_numer' ), 10, 2 );
@@ -314,6 +318,33 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
314
  return $complete_document;
315
  }
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  /**
318
  * Create & render DOMPDF object
319
  */
@@ -331,9 +362,12 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
331
  }
332
 
333
  $dompdf = new DOMPDF();
334
- $dompdf->load_html($this->process_template( $template_type, $order_ids ));
 
335
  $dompdf->set_paper( $paper_size, $paper_orientation );
 
336
  $dompdf->render();
 
337
  do_action( 'wpo_wcpdf_after_pdf', $template_type );
338
 
339
  // Try to clean up a bit of memory
@@ -582,7 +616,10 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
582
 
583
  // add invoice number if it doesn't exist
584
  if ( empty($invoice_number) || !isset($invoice_number) ) {
585
- $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $this->template_settings['next_invoice_number'], $order_id );
 
 
 
586
 
587
  if ( empty($next_invoice_number) ) {
588
  // First time! We start numbering from order_number or order_id
@@ -622,12 +659,11 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
622
  update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
623
 
624
  // increase next_order_number
625
- $template_settings = apply_filters( 'wpml_unfiltered_admin_string', get_option( 'wpo_wcpdf_template_settings' ), 'wpo_wcpdf_template_settings' );
626
- // fix wpml bug
627
- $template_settings = maybe_unserialize($template_settings);
628
-
629
- $template_settings['next_invoice_number'] = $this->template_settings['next_invoice_number'] = $invoice_number+1;
630
- update_option( 'wpo_wcpdf_template_settings', $template_settings );
631
  }
632
 
633
  // store invoice_number in class object
47
  require_once( $this->template_path . '/template-functions.php' );
48
  }
49
 
50
+ // make page number replacements
51
+ add_action( 'wpo_wcpdf_processed_template_html', array($this, 'clear_page_number_styles' ), 10, 3 );
52
+ add_action( 'wpo_wcpdf_after_dompdf_render', array($this, 'page_number_replacements' ), 9, 4 );
53
+
54
  add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ));
55
  add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3);
56
  add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_numer' ), 10, 2 );
318
  return $complete_document;
319
  }
320
 
321
+ /**
322
+ * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
323
+ */
324
+ public function clear_page_number_styles ( $html, $template_type, $order_ids ) {
325
+ $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">{{PAGE_COUNT}}</span>', $html);
326
+ $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
327
+ return $html;
328
+ }
329
+
330
+ /**
331
+ * Replace {{PAGE_COUNT}} placeholder with total page count
332
+ */
333
+ public function page_number_replacements ( $dompdf, $html, $template_type, $order_ids ) {
334
+ $placeholder = '{{PAGE_COUNT}}';
335
+
336
+ // check if placeholder is used
337
+ if (strpos($html, $placeholder) !== false ) {
338
+ foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
339
+ if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false) {
340
+ $object["c"] = str_replace( $placeholder , $dompdf->get_canvas()->get_page_count() , $object["c"] );
341
+ }
342
+ }
343
+ }
344
+
345
+ return $dompdf;
346
+ }
347
+
348
  /**
349
  * Create & render DOMPDF object
350
  */
362
  }
363
 
364
  $dompdf = new DOMPDF();
365
+ $html = apply_filters( 'wpo_wcpdf_processed_template_html', $this->process_template( $template_type, $order_ids ), $template_type, $order_ids );
366
+ $dompdf->load_html( $html );
367
  $dompdf->set_paper( $paper_size, $paper_orientation );
368
+ $dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $html, $template_type, $order_ids );
369
  $dompdf->render();
370
+ $dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $html, $template_type, $order_ids );
371
  do_action( 'wpo_wcpdf_after_pdf', $template_type );
372
 
373
  // Try to clean up a bit of memory
616
 
617
  // add invoice number if it doesn't exist
618
  if ( empty($invoice_number) || !isset($invoice_number) ) {
619
+ global $wpdb;
620
+ // making direct DB call to avoid caching issues
621
+ $next_invoice_number = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'wpo_wcpdf_next_invoice_number' ) );
622
+ $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $next_invoice_number, $order_id );
623
 
624
  if ( empty($next_invoice_number) ) {
625
  // First time! We start numbering from order_number or order_id
659
  update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
660
 
661
  // increase next_order_number
662
+ $update_args = array(
663
+ 'option_value' => $invoice_number + 1,
664
+ 'autoload' => 'yes',
665
+ );
666
+ $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => 'wpo_wcpdf_next_invoice_number' ) );
 
667
  }
668
 
669
  // store invoice_number in class object
includes/class-wcpdf-settings.php CHANGED
@@ -535,20 +535,40 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Settings' ) ) {
535
  )
536
  );
537
 
 
 
538
  add_settings_field(
539
  'next_invoice_number',
540
  __( 'Next invoice number (without prefix/suffix etc.)', 'wpo_wcpdf' ),
541
- array( &$this, 'text_element_callback' ),
542
  $option,
543
  'invoice',
544
  array(
545
- 'menu' => $option,
546
  'id' => 'next_invoice_number',
547
  'size' => '10',
548
  'description' => __( 'This is the number that will be used on the next invoice that is created. By default, numbering starts from the WooCommerce Order Number of the first invoice that is created and increases for every new invoice. Note that if you override this and set it lower than the highest (PDF) invoice number, this could create double invoice numbers!', 'wpo_wcpdf' ),
549
  )
550
  );
551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
  add_settings_field(
553
  'invoice_number_formatting',
554
  __( 'Invoice number format', 'wpo_wcpdf' ),
@@ -695,27 +715,6 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Settings' ) ) {
695
  // Register settings.
696
  register_setting( $option, $option, array( &$this, 'validate_options' ) );
697
 
698
- $option_values = get_option($option);
699
- // determine highest invoice number if option not set
700
- if ( !isset( $option_values['next_invoice_number']) ) {
701
- // Based on code from WooCommerce Sequential Order Numbers
702
- global $wpdb;
703
- // get highest invoice_number in postmeta table
704
- $max_invoice_number = $wpdb->get_var( 'SELECT max(cast(meta_value as UNSIGNED)) from ' . $wpdb->postmeta . ' where meta_key="_wcpdf_invoice_number"' );
705
- // get highest order_number in postmeta table
706
- // $max_order_number = $wpdb->get_var( 'SELECT max(cast(meta_value as UNSIGNED)) from ' . $wpdb->postmeta . ' where meta_key="_order_number"' );
707
- // get highest post_id with type shop_order in post table
708
- // $max_order_id = $wpdb->get_var( 'SELECT max(cast(ID as UNSIGNED)) from ' . $wpdb->posts . ' where post_type="shop_order"' );
709
-
710
- $next_invoice_number = '';
711
-
712
- if ( isset($max_invoice_number) && !empty($max_invoice_number) ) {
713
- $next_invoice_number = $max_invoice_number+1;
714
- }
715
-
716
- $option_values['next_invoice_number'] = $next_invoice_number;
717
- update_option( $option, $option_values );
718
- }
719
  /**************************************/
720
  /******** DEBUG/STATUS SETTINGS *******/
721
  /**************************************/
@@ -883,7 +882,32 @@ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Settings' ) ) {
883
 
884
  echo $html;
885
  }
 
 
 
 
 
 
 
886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
  // Text element callback.
888
  public function textarea_element_callback( $args ) {
889
  $menu = $args['menu'];
535
  )
536
  );
537
 
538
+ // invoice number is stored separately for direct retrieval
539
+ register_setting( $option, 'wpo_wcpdf_next_invoice_number', array( &$this, 'validate_options' ) );
540
  add_settings_field(
541
  'next_invoice_number',
542
  __( 'Next invoice number (without prefix/suffix etc.)', 'wpo_wcpdf' ),
543
+ array( &$this, 'singular_text_element_callback' ),
544
  $option,
545
  'invoice',
546
  array(
547
+ 'menu' => 'wpo_wcpdf_next_invoice_number',
548
  'id' => 'next_invoice_number',
549
  'size' => '10',
550
  'description' => __( 'This is the number that will be used on the next invoice that is created. By default, numbering starts from the WooCommerce Order Number of the first invoice that is created and increases for every new invoice. Note that if you override this and set it lower than the highest (PDF) invoice number, this could create double invoice numbers!', 'wpo_wcpdf' ),
551
  )
552
  );
553
 
554
+ // first time invoice number
555
+ $next_invoice_number = get_option('wpo_wcpdf_next_invoice_number');
556
+ // determine highest invoice number if option not set
557
+ if ( !isset( $next_invoice_number ) ) {
558
+ // Based on code from WooCommerce Sequential Order Numbers
559
+ global $wpdb;
560
+ // get highest invoice_number in postmeta table
561
+ $max_invoice_number = $wpdb->get_var( 'SELECT max(cast(meta_value as UNSIGNED)) from ' . $wpdb->postmeta . ' where meta_key="_wcpdf_invoice_number"' );
562
+
563
+ if ( !empty($max_invoice_number) ) {
564
+ $next_invoice_number = $max_invoice_number+1;
565
+ } else {
566
+ $next_invoice_number = '';
567
+ }
568
+
569
+ update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
570
+ }
571
+
572
  add_settings_field(
573
  'invoice_number_formatting',
574
  __( 'Invoice number format', 'wpo_wcpdf' ),
715
  // Register settings.
716
  register_setting( $option, $option, array( &$this, 'validate_options' ) );
717
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
718
  /**************************************/
719
  /******** DEBUG/STATUS SETTINGS *******/
720
  /**************************************/
882
 
883
  echo $html;
884
  }
885
+
886
+ // Single text option (not part of any settings array)
887
+ public function singular_text_element_callback( $args ) {
888
+ $menu = $args['menu'];
889
+ $id = $args['id'];
890
+ $size = isset( $args['size'] ) ? $args['size'] : '25';
891
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
892
 
893
+ $option = get_option( $menu );
894
+
895
+ if ( isset( $option ) ) {
896
+ $current = $option;
897
+ } else {
898
+ $current = isset( $args['default'] ) ? $args['default'] : '';
899
+ }
900
+
901
+ $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $menu, $current, $size, $class );
902
+
903
+ // Displays option description.
904
+ if ( isset( $args['description'] ) ) {
905
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
906
+ }
907
+
908
+ echo $html;
909
+ }
910
+
911
  // Text element callback.
912
  public function textarea_element_callback( $args ) {
913
  $menu = $args['menu'];
includes/class-wcpdf-writepanels.php CHANGED
@@ -82,7 +82,8 @@ if ( !class_exists( 'WooCommerce_PDF_Invoices_Writepanels' ) ) {
82
  wp_localize_script(
83
  'wpo-wcpdf',
84
  'wpo_wcpdf_ajax',
85
- array(
 
86
  'ajaxurl' => admin_url( 'admin-ajax.php' ), // URL to WordPress ajax handling page
87
  'nonce' => wp_create_nonce('generate_wpo_wcpdf'),
88
  'bulk_actions' => array_keys( apply_filters( 'wpo_wcpdf_bulk_actions', $this->bulk_actions ) ),
82
  wp_localize_script(
83
  'wpo-wcpdf',
84
  'wpo_wcpdf_ajax',
85
+ array(
86
+ // 'ajaxurl' => add_query_arg( 'action', 'generate_wpo_wcpdf', admin_url( 'admin-ajax.php' ) ), // URL to WordPress ajax handling page
87
  'ajaxurl' => admin_url( 'admin-ajax.php' ), // URL to WordPress ajax handling page
88
  'nonce' => wp_create_nonce('generate_wpo_wcpdf'),
89
  'bulk_actions' => array_keys( apply_filters( 'wpo_wcpdf_bulk_actions', $this->bulk_actions ) ),
js/script.js CHANGED
@@ -18,7 +18,13 @@ jQuery(document).ready(function($) {
18
  }
19
 
20
  var order_ids=checked.join('x');
21
- url = wpo_wcpdf_ajax.ajaxurl+'?action=generate_wpo_wcpdf&template_type='+template+'&order_ids='+order_ids+'&_wpnonce='+wpo_wcpdf_ajax.nonce;
 
 
 
 
 
 
22
  window.open(url,'_blank');
23
  }
24
  });
18
  }
19
 
20
  var order_ids=checked.join('x');
21
+
22
+ if (wpo_wcpdf_ajax.ajaxurl.indexOf("?") != -1) {
23
+ url = wpo_wcpdf_ajax.ajaxurl+'&action=generate_wpo_wcpdf&template_type='+template+'&order_ids='+order_ids+'&_wpnonce='+wpo_wcpdf_ajax.nonce;
24
+ } else {
25
+ url = wpo_wcpdf_ajax.ajaxurl+'?action=generate_wpo_wcpdf&template_type='+template+'&order_ids='+order_ids+'&_wpnonce='+wpo_wcpdf_ajax.nonce;
26
+ }
27
+
28
  window.open(url,'_blank');
29
  }
30
  });
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: pomegranate
3
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
4
  Requires at least: 3.5
5
  Tested up to: 4.4.1
6
- Stable tag: 1.5.27
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -235,6 +235,11 @@ This usually only happens on batch actions. PDF creation is a memory intensive j
235
 
236
  == Changelog ==
237
 
 
 
 
 
 
238
  = 1.5.27 =
239
  * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
240
  * Feature: WooCommerce Order Status & Actions Manager emails compatibility
3
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
4
  Requires at least: 3.5
5
  Tested up to: 4.4.1
6
+ Stable tag: 1.5.28
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
235
 
236
  == Changelog ==
237
 
238
+ = 1.5.28 =
239
+ * Tweak: the 'Next invoice number' is now stored separately in the database for faster and more reliable retrieval. Circumventing any caching, this should prevent duplicate invoice numbers.
240
+ * Fix: Bulk actions plugin conflicts
241
+ * Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
242
+
243
  = 1.5.27 =
244
  * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
245
  * Feature: WooCommerce Order Status & Actions Manager emails compatibility
templates/pdf/Simple/style.css CHANGED
@@ -267,4 +267,12 @@ table.totals tr.payment_method {
267
  border-top: 0.1mm solid gray;
268
  margin-bottom: 0;
269
  padding-top: 2mm;
 
 
 
 
 
 
 
 
270
  }
267
  border-top: 0.1mm solid gray;
268
  margin-bottom: 0;
269
  padding-top: 2mm;
270
+ }
271
+
272
+ /* page numbers */
273
+ .pagenum:before {
274
+ content: counter(page);
275
+ }
276
+ .pagenum,.pagecount {
277
+ font-family: sans-serif;
278
  }
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 1.5.27
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
@@ -33,7 +33,7 @@ if ( !class_exists( 'WooCommerce_PDF_Invoices' ) ) {
33
  self::$plugin_basename = plugin_basename(__FILE__);
34
  self::$plugin_url = plugin_dir_url(self::$plugin_basename);
35
  self::$plugin_path = trailingslashit(dirname(__FILE__));
36
- self::$version = '1.5.27';
37
 
38
  // load the localisation & classes
39
  add_action( 'plugins_loaded', array( $this, 'translations' ) ); // or use init?
@@ -205,6 +205,12 @@ if ( !class_exists( 'WooCommerce_PDF_Invoices' ) ) {
205
  $this->export->copy_fonts( $font_path );
206
  }
207
 
 
 
 
 
 
 
208
  }
209
 
210
  /***********************************************************************/
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 1.5.28
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
33
  self::$plugin_basename = plugin_basename(__FILE__);
34
  self::$plugin_url = plugin_dir_url(self::$plugin_basename);
35
  self::$plugin_path = trailingslashit(dirname(__FILE__));
36
+ self::$version = '1.5.28';
37
 
38
  // load the localisation & classes
39
  add_action( 'plugins_loaded', array( $this, 'translations' ) ); // or use init?
205
  $this->export->copy_fonts( $font_path );
206
  }
207
 
208
+ // 1.5.28 update: copy next invoice number to separate setting
209
+ if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
210
+ $template_settings = get_option( 'wpo_wcpdf_template_settings' );
211
+ $next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
212
+ update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
213
+ }
214
  }
215
 
216
  /***********************************************************************/