WooCommerce PDF Invoices & Packing Slips - Version 2.2.10

Version Description

  • Fix: Possible conflict with latest Subscriptions
  • Fix: Load correct translations when admin user profile language is set to different locale
  • Fix: Use file lock to prevent parallel processes creating the same attachment file
  • Fix: Prevent notices for incorrectly loaded email classes
  • Feature: Allow different invoice number column sorting methods by filter
  • Feature: Filter for global prevention of creating specific document (wpo_wcpdf_document_is_allowed)
Download this release

Release Info

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

Code changes from version 2.2.9 to 2.2.10

includes/class-wcpdf-admin.php CHANGED
@@ -169,13 +169,14 @@ class Admin {
169
  $listing_actions = array();
170
  $documents = WPO_WCPDF()->documents->get_documents();
171
  foreach ($documents as $document) {
172
- $document->read_data( $order );
173
- $listing_actions[$document->get_type()] = array(
174
- 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . WCX_Order::get_id( $order ) ), 'generate_wpo_wcpdf' ),
175
- 'img' => !empty($document->icon) ? $document->icon : WPO_WCPDF()->plugin_url() . "/assets/images/generic_document.png",
176
- 'alt' => "PDF " . $document->get_title(),
177
- 'exists' => $document->exists(),
178
- );
 
179
  }
180
 
181
  $listing_actions = apply_filters( 'wpo_wcpdf_listing_actions', $listing_actions, $order );
@@ -272,6 +273,12 @@ class Admin {
272
  * Resend order emails
273
  */
274
  public function send_order_email_meta_box( $post ) {
 
 
 
 
 
 
275
  ?>
276
  <ul class="wpo_wcpdf_send_emails submitbox">
277
  <li class="wide" id="actions">
@@ -313,13 +320,14 @@ class Admin {
313
  $documents = WPO_WCPDF()->documents->get_documents();
314
  $order = WCX::get_order( $post->ID );
315
  foreach ($documents as $document) {
316
- $document->read_data( $order );
317
- $meta_box_actions[$document->get_type()] = array(
318
- 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . $post_id ), 'generate_wpo_wcpdf' ),
319
- 'alt' => esc_attr( "PDF " . $document->get_title() ),
320
- 'title' => "PDF " . $document->get_title(),
321
- 'exists' => $document->exists(),
322
- );
 
323
  }
324
 
325
  $meta_box_actions = apply_filters( 'wpo_wcpdf_meta_box_actions', $meta_box_actions, $post_id );
@@ -548,8 +556,8 @@ class Admin {
548
  }
549
  $orderby = $query->get( 'orderby');
550
  if( 'pdf_invoice_number' == $orderby ) {
551
- $query->set('meta_key','_wcpdf_invoice_number');
552
- $query->set('orderby','meta_value');
553
  }
554
  }
555
 
@@ -564,7 +572,7 @@ class Admin {
564
  if ( 'pdf_invoice_number' === $query_vars['orderby'] ) {
565
  $query_vars = array_merge( $query_vars, array(
566
  'meta_key' => '_wcpdf_invoice_number',
567
- 'orderby' => 'meta_value',
568
  ) );
569
  }
570
  }
169
  $listing_actions = array();
170
  $documents = WPO_WCPDF()->documents->get_documents();
171
  foreach ($documents as $document) {
172
+ if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
173
+ $listing_actions[$document->get_type()] = array(
174
+ 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . WCX_Order::get_id( $order ) ), 'generate_wpo_wcpdf' ),
175
+ 'img' => !empty($document->icon) ? $document->icon : WPO_WCPDF()->plugin_url() . "/assets/images/generic_document.png",
176
+ 'alt' => "PDF " . $document->get_title(),
177
+ 'exists' => $document->exists(),
178
+ );
179
+ }
180
  }
181
 
182
  $listing_actions = apply_filters( 'wpo_wcpdf_listing_actions', $listing_actions, $order );
273
  * Resend order emails
274
  */
275
  public function send_order_email_meta_box( $post ) {
276
+ global $theorder;
277
+ // This is used by some callbacks attached to hooks such as woocommerce_resend_order_emails_available
278
+ // which rely on the global to determine if emails should be displayed for certain orders.
279
+ if ( ! is_object( $theorder ) ) {
280
+ $theorder = wc_get_order( $post->ID );
281
+ }
282
  ?>
283
  <ul class="wpo_wcpdf_send_emails submitbox">
284
  <li class="wide" id="actions">
320
  $documents = WPO_WCPDF()->documents->get_documents();
321
  $order = WCX::get_order( $post->ID );
322
  foreach ($documents as $document) {
323
+ if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
324
+ $meta_box_actions[$document->get_type()] = array(
325
+ 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . $post_id ), 'generate_wpo_wcpdf' ),
326
+ 'alt' => esc_attr( "PDF " . $document->get_title() ),
327
+ 'title' => "PDF " . $document->get_title(),
328
+ 'exists' => $document->exists(),
329
+ );
330
+ }
331
  }
332
 
333
  $meta_box_actions = apply_filters( 'wpo_wcpdf_meta_box_actions', $meta_box_actions, $post_id );
556
  }
557
  $orderby = $query->get( 'orderby');
558
  if( 'pdf_invoice_number' == $orderby ) {
559
+ $query->set( 'meta_key', '_wcpdf_invoice_number' );
560
+ $query->set( 'orderby', apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ) );
561
  }
562
  }
563
 
572
  if ( 'pdf_invoice_number' === $query_vars['orderby'] ) {
573
  $query_vars = array_merge( $query_vars, array(
574
  'meta_key' => '_wcpdf_invoice_number',
575
+ 'orderby' => apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ),
576
  ) );
577
  }
578
  }
includes/class-wcpdf-main.php CHANGED
@@ -89,6 +89,7 @@ class Main {
89
 
90
  // reload translations because WC may have switched to site locale (by setting the plugin_locale filter to site locale in wc_switch_to_site_locale())
91
  WPO_WCPDF()->translations();
 
92
 
93
  $attach_to_document_types = $this->get_documents_for_email( $email_id, $order );
94
  foreach ( $attach_to_document_types as $document_type ) {
@@ -109,15 +110,32 @@ class Main {
109
  if ($filemtime = filemtime($pdf_path)) {
110
  $time_difference = time() - $filemtime;
111
  if ( $time_difference < apply_filters( 'wpo_wcpdf_reuse_attachment_age', 60 ) ) {
112
- $attachments[] = $pdf_path;
113
- continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
  }
116
  }
117
 
118
  // get pdf data & store
119
  $pdf_data = $document->get_pdf();
120
- file_put_contents ( $pdf_path, $pdf_data );
121
  $attachments[] = $pdf_path;
122
 
123
  do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $document_type, $document );
@@ -138,6 +156,18 @@ class Main {
138
  return $attachments;
139
  }
140
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  public function get_documents_for_email( $email_id, $order ) {
142
  $documents = WPO_WCPDF()->documents->get_documents();
143
 
89
 
90
  // reload translations because WC may have switched to site locale (by setting the plugin_locale filter to site locale in wc_switch_to_site_locale())
91
  WPO_WCPDF()->translations();
92
+ do_action( 'wpo_wcpdf_reload_attachment_translations' );
93
 
94
  $attach_to_document_types = $this->get_documents_for_email( $email_id, $order );
95
  foreach ( $attach_to_document_types as $document_type ) {
110
  if ($filemtime = filemtime($pdf_path)) {
111
  $time_difference = time() - $filemtime;
112
  if ( $time_difference < apply_filters( 'wpo_wcpdf_reuse_attachment_age', 60 ) ) {
113
+ // check if file is still being written to
114
+ $fp = fopen($pdf_path, 'r+');
115
+ if ( $locked = $this->file_is_locked( $fp ) ) {
116
+ // optional delay (ms) to double check if the write process is finished
117
+ $delay = intval( apply_filters( 'wpo_wcpdf_attachment_locked_file_delay', 250 ) );
118
+ if ( $delay > 0 ) {
119
+ usleep( $delay * 1000 );
120
+ $locked = $this->file_is_locked( $fp );
121
+ }
122
+ }
123
+ fclose($fp);
124
+
125
+ if ( !$locked ) {
126
+ $attachments[] = $pdf_path;
127
+ continue;
128
+ } else {
129
+ // make sure this gets logged
130
+ throw new \Exception("Failed attachment, file locked");
131
+ }
132
  }
133
  }
134
  }
135
 
136
  // get pdf data & store
137
  $pdf_data = $document->get_pdf();
138
+ file_put_contents ( $pdf_path, $pdf_data, LOCK_EX );
139
  $attachments[] = $pdf_path;
140
 
141
  do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $document_type, $document );
156
  return $attachments;
157
  }
158
 
159
+ public function file_is_locked( $fp ) {
160
+ if (!flock($fp, LOCK_EX|LOCK_NB, $wouldblock)) {
161
+ if ($wouldblock) {
162
+ return true; // file is locked
163
+ } else {
164
+ return true; // can't lock for whatever reason (could be locked in Windows + PHP5.3)
165
+ }
166
+ } else {
167
+ return false; // not locked
168
+ }
169
+ }
170
+
171
  public function get_documents_for_email( $email_id, $order ) {
172
  $documents = WPO_WCPDF()->documents->get_documents();
173
 
includes/documents/abstract-wcpdf-order-document.php CHANGED
@@ -278,6 +278,10 @@ abstract class Order_Document {
278
  do_action( 'wpo_wcpdf_delete_document', $this );
279
  }
280
 
 
 
 
 
281
  public function exists() {
282
  return !empty( $this->data['date'] );
283
  }
@@ -724,6 +728,9 @@ abstract class Order_Document {
724
 
725
  $emails = array();
726
  foreach ($wc_emails as $class => $email) {
 
 
 
727
  if ( !in_array( $email->id, $non_order_emails ) ) {
728
  switch ($email->id) {
729
  case 'new_order':
278
  do_action( 'wpo_wcpdf_delete_document', $this );
279
  }
280
 
281
+ public function is_allowed() {
282
+ return apply_filters( 'wpo_wcpdf_document_is_allowed', true, $this );
283
+ }
284
+
285
  public function exists() {
286
  return !empty( $this->data['date'] );
287
  }
728
 
729
  $emails = array();
730
  foreach ($wc_emails as $class => $email) {
731
+ if ( !is_object( $email ) ) {
732
+ continue;
733
+ }
734
  if ( !in_array( $email->id, $non_order_emails ) ) {
735
  switch ($email->id) {
736
  case 'new_order':
includes/documents/class-wcpdf-bulk-document.php CHANGED
@@ -75,8 +75,9 @@ class Bulk_Document {
75
 
76
  $order = WCX::get_order( $order_id );
77
 
78
- $document = wcpdf_get_document( $this->get_type(), $order, true );
79
- $html_content[ $key ] = $document->get_html( array( 'wrap_html_content' => false ) );
 
80
  }
81
 
82
  // get wrapper document & insert body content
75
 
76
  $order = WCX::get_order( $order_id );
77
 
78
+ if ( $document = wcpdf_get_document( $this->get_type(), $order, true ) ) {
79
+ $html_content[ $key ] = $document->get_html( array( 'wrap_html_content' => false ) );
80
+ }
81
  }
82
 
83
  // get wrapper document & insert body content
includes/wcpdf-functions.php CHANGED
@@ -46,11 +46,14 @@ function wcpdf_get_document( $document_type, $order, $init = false ) {
46
  do_action( 'wpo_wcpdf_process_template_order', $document_type, WCX_Order::get_id( $order ) );
47
  $document = WPO_WCPDF()->documents->get_document( $document_type, $order );
48
 
 
 
 
 
49
  if ( $init && !$document->exists() ) {
50
  $document->init();
51
  $document->save();
52
  }
53
- // $document->read_data( $order ); // isn't data already read from construct?
54
  return $document;
55
  } else {
56
  // order ids array changed, continue processing that array
@@ -74,6 +77,11 @@ function wcpdf_get_document( $document_type, $order, $init = false ) {
74
  $order = WCX::get_order( $order_id );
75
 
76
  $document = WPO_WCPDF()->documents->get_document( $document_type, $order );
 
 
 
 
 
77
  if ( $init && !$document->exists() ) {
78
  $document->init();
79
  $document->save();
46
  do_action( 'wpo_wcpdf_process_template_order', $document_type, WCX_Order::get_id( $order ) );
47
  $document = WPO_WCPDF()->documents->get_document( $document_type, $order );
48
 
49
+ if ( !$document->is_allowed() ) {
50
+ return false;
51
+ }
52
+
53
  if ( $init && !$document->exists() ) {
54
  $document->init();
55
  $document->save();
56
  }
 
57
  return $document;
58
  } else {
59
  // order ids array changed, continue processing that array
77
  $order = WCX::get_order( $order_id );
78
 
79
  $document = WPO_WCPDF()->documents->get_document( $document_type, $order );
80
+
81
+ if ( !$document->is_allowed() ) {
82
+ return false;
83
+ }
84
+
85
  if ( $init && !$document->exists() ) {
86
  $document->init();
87
  $document->save();
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice,
5
  Requires at least: 3.5
6
  Tested up to: 5.1
7
  Requires PHP: 5.3
8
- Stable tag: 2.2.9
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -103,6 +103,14 @@ There's a setting on the Status tab of the settings page that allows you to togg
103
 
104
  == Changelog ==
105
 
 
 
 
 
 
 
 
 
106
  = 2.2.9 =
107
  * Feature: Added customer note email to attachment options
108
  * Fix: Prevent empty invoice dates from being saved as 1970 (fallback to current date/time)
5
  Requires at least: 3.5
6
  Tested up to: 5.1
7
  Requires PHP: 5.3
8
+ Stable tag: 2.2.10
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
103
 
104
  == Changelog ==
105
 
106
+ = 2.2.10 =
107
+ * Fix: Possible conflict with latest Subscriptions
108
+ * Fix: Load correct translations when admin user profile language is set to different locale
109
+ * Fix: Use file lock to prevent parallel processes creating the same attachment file
110
+ * Fix: Prevent notices for incorrectly loaded email classes
111
+ * Feature: Allow different invoice number column sorting methods by filter
112
+ * Feature: Filter for global prevention of creating specific document (`wpo_wcpdf_document_is_allowed`)
113
+
114
  = 2.2.9 =
115
  * Feature: Added customer note email to attachment options
116
  * Fix: Prevent empty invoice dates from being saved as 1970 (fallback to current date/time)
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: 2.2.9
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
@@ -21,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
21
 
22
  class WPO_WCPDF {
23
 
24
- public $version = '2.2.9';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
 
@@ -72,7 +72,8 @@ class WPO_WCPDF {
72
  * Note: the first-loaded translation file overrides any following ones if the same translation is present
73
  */
74
  public function translations() {
75
- $locale = apply_filters( 'plugin_locale', get_locale(), 'woocommerce-pdf-invoices-packing-slips' );
 
76
  $dir = trailingslashit( WP_LANG_DIR );
77
 
78
  $textdomains = array( 'woocommerce-pdf-invoices-packing-slips' );
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: 2.2.10
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.2.10';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
 
72
  * Note: the first-loaded translation file overrides any following ones if the same translation is present
73
  */
74
  public function translations() {
75
+ $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
76
+ $locale = apply_filters( 'plugin_locale', $locale, 'woocommerce-pdf-invoices-packing-slips' );
77
  $dir = trailingslashit( WP_LANG_DIR );
78
 
79
  $textdomains = array( 'woocommerce-pdf-invoices-packing-slips' );