WooCommerce PDF Invoices & Packing Slips - Version 2.7.2

Version Description

  • Fix: Update invoice number and date when regenerating document from edit mode
  • Fix: Prevent infinite loop when temporary folder is not writable
  • Fix: Prevent layout issues when custom order data exceeds column width
  • Fix: Error when PHP Ctype extension is not installed
  • Tested up to WooCommerce 4.8 & WP 5.6
Download this release

Release Info

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

Code changes from version 2.7.1 to 2.7.2

assets/css/order-styles.css CHANGED
@@ -38,10 +38,16 @@
38
  }
39
  }
40
 
 
 
 
 
 
 
41
  #wpo_wcpdf-data-input-box h4 {
42
  font-size: 14px;
43
  line-height: 1.4;
44
- margin: 1.5em 0 0 0;
45
  }
46
 
47
  #wpo_wcpdf-data-input-box p {
@@ -52,6 +58,19 @@
52
  width: auto;
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  .wcpdf-data-fields .read-only {
56
  height:auto;
57
  display:block;
38
  }
39
  }
40
 
41
+ #wpo_wcpdf-data-input-box > .inside {
42
+ margin: 0;
43
+ padding: 10px 0;
44
+ background-color: #f8f8f8;
45
+ }
46
+
47
  #wpo_wcpdf-data-input-box h4 {
48
  font-size: 14px;
49
  line-height: 1.4;
50
+ margin: 0;
51
  }
52
 
53
  #wpo_wcpdf-data-input-box p {
58
  width: auto;
59
  }
60
 
61
+ .wcpdf-data-fields {
62
+ margin-left: 10px;
63
+ margin-right: 10px;
64
+ padding: 10px;
65
+ margin-bottom: 10px;
66
+ background-color: white;
67
+ border-bottom: 1px solid #dfdfdf;
68
+ }
69
+
70
+ .wcpdf-data-fields:last-child {
71
+ margin-bottom: 0;
72
+ }
73
+
74
  .wcpdf-data-fields .read-only {
75
  height:auto;
76
  display:block;
assets/js/order-script.js CHANGED
@@ -33,7 +33,11 @@ jQuery(document).ready(function($) {
33
 
34
  // enable invoice number edit if user initiated
35
  $( ".wpo-wcpdf-set-date-number, .wpo-wcpdf-edit-date-number, .wpo-wcpdf-edit-document-notes" ).click(function() {
36
- $form = $(this).closest('.wcpdf-data-fields');
 
 
 
 
37
  // check visibility
38
  if( $form.find(".read-only").is(":visible") ) {
39
  $form.find(".read-only").hide();
@@ -85,19 +89,35 @@ jQuery(document).ready(function($) {
85
  $(this).addClass('wcpdf-regenerate-spin');
86
  $form = $(this).closest('.wcpdf-data-fields');
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  // Make sure all feedback icons are hidden before each call
89
  $form.find('.document-action-success, .document-action-failed').hide();
90
 
91
  $.ajax({
92
- url: wpo_wcpdf_ajax.ajaxurl,
93
- data: {
94
- action : 'wpo_wcpdf_regenerate_document',
95
- security: $(this).data('nonce'),
96
- document: $form.data('document'),
97
- order_id: $form.data('order_id')
 
98
  },
99
- type: 'POST',
100
- context: $form,
101
  success: function( response ) {
102
  if ( response.success ) {
103
  $(this).find('.document-action-success').show();
33
 
34
  // enable invoice number edit if user initiated
35
  $( ".wpo-wcpdf-set-date-number, .wpo-wcpdf-edit-date-number, .wpo-wcpdf-edit-document-notes" ).click(function() {
36
+ $form = $(this).closest('.wcpdf-data-fields-section');
37
+ if ($form.length == 0) { // no section, take overall wrapper
38
+ $form = $(this).closest('.wcpdf-data-fields');
39
+ }
40
+
41
  // check visibility
42
  if( $form.find(".read-only").is(":visible") ) {
43
  $form.find(".read-only").hide();
89
  $(this).addClass('wcpdf-regenerate-spin');
90
  $form = $(this).closest('.wcpdf-data-fields');
91
 
92
+ // create an object with the form inputs data
93
+ form_inputs_data = {};
94
+ $form.find(':input').each( function() {
95
+ name = $(this).attr("name");
96
+ name = name.split('[', 1)[0]; // for credit-note array []
97
+ value = $(this).val();
98
+ form_inputs_data[name] = value;
99
+ } );
100
+
101
+ // convert data to json string
102
+ form_data_json = JSON.stringify( form_inputs_data );
103
+
104
+ // create an object with the data attributes
105
+ form_data_attributes = $form.data();
106
+
107
  // Make sure all feedback icons are hidden before each call
108
  $form.find('.document-action-success, .document-action-failed').hide();
109
 
110
  $.ajax({
111
+ url: wpo_wcpdf_ajax.ajaxurl,
112
+ data: {
113
+ action: 'wpo_wcpdf_regenerate_document',
114
+ security: $(this).data('nonce'),
115
+ form_data: form_data_json,
116
+ order_id: form_data_attributes.order_id,
117
+ document_type: form_data_attributes.document,
118
  },
119
+ type: 'POST',
120
+ context: $form,
121
  success: function( response ) {
122
  if ( response.success ) {
123
  $(this).find('.document-action-success').show();
includes/class-wcpdf-admin.php CHANGED
@@ -272,7 +272,7 @@ class Admin {
272
  // Invoice number & date
273
  add_meta_box(
274
  'wpo_wcpdf-data-input-box',
275
- __( 'PDF Invoice data', 'woocommerce-pdf-invoices-packing-slips' ),
276
  array( $this, 'data_input_box_content' ),
277
  'shop_order',
278
  'normal',
@@ -375,67 +375,65 @@ class Admin {
375
  ?>
376
 
377
  <div class="wcpdf-data-fields" data-document="invoice" data-order_id="<?php echo WCX_Order::get_id( $order ); ?>">
378
- <h4>
379
- <?php echo $invoice->get_title(); ?><?php if ($invoice->exists()) : ?>
380
- <span class="wpo-wcpdf-edit-date-number dashicons dashicons-edit"></span>
381
- <span class="wpo-wcpdf-delete-document dashicons dashicons-trash" data-nonce="<?php echo wp_create_nonce( "wpo_wcpdf_delete_document" ); ?>"></span>
382
- <?php do_action( 'wpo_wcpdf_document_actions', $invoice ); ?>
383
- <?php endif; ?>
384
- </h4>
385
-
386
- <!-- Read only -->
387
- <div class="read-only">
388
- <?php if ($invoice->exists()) : ?>
389
- <div class="invoice-number">
390
- <p class="form-field _wcpdf_invoice_number_field ">
391
- <p>
392
- <span><strong><?php _e( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</strong></span>
393
- <span><?php if (!empty($invoice_number)) echo $invoice_number->get_formatted(); ?></span>
 
 
394
  </p>
395
- </p>
396
- </div>
397
 
398
- <div class="invoice-date">
399
- <p class="form-field form-field-wide">
400
- <p>
401
- <span><strong><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
402
- <span><?php if (!empty($invoice_date)) echo $invoice_date->date_i18n( wc_date_format().' @ '.wc_time_format() ); ?></span>
 
403
  </p>
404
- </p>
405
- </div>
406
-
407
- <?php do_action( 'wpo_wcpdf_meta_box_after_document_data', $invoice, $order ); ?>
408
 
409
- <?php else : ?>
410
- <span class="wpo-wcpdf-set-date-number button"><?php _e( 'Set invoice number & date', 'woocommerce-pdf-invoices-packing-slips' ) ?></span>
411
- <?php endif; ?>
412
- </div>
413
 
414
- <!-- Editable -->
415
- <div class="editable">
416
- <p class="form-field _wcpdf_invoice_number_field ">
417
- <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
418
- <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
419
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>" disabled="disabled">
420
  <?php else : ?>
421
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled">
422
  <?php endif; ?>
423
- </p>
424
- <p class="form-field form-field-wide">
425
- <label for="wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
426
- <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
427
- <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" disabled="disabled"/>@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
428
- <?php else : ?>
429
- <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" disabled="disabled" value="<?php echo date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo date_i18n( 'H' ); ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
430
- <?php endif; ?>
431
- </p>
432
- </div>
433
- </div>
434
-
435
- <?php do_action( 'wpo_wcpdf_meta_box_before_document_notes', $invoice, $order ); ?>
436
 
437
- <div class="wcpdf-data-fields" data-document="invoice" data-order_id="<?php echo WCX_Order::get_id( $order ); ?>">
438
- <div class="invoice-notes">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  <p class="form-field form-field-wide">
440
  <div>
441
  <span><strong><?php _e( 'Notes (printed in the invoice):', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
@@ -451,17 +449,17 @@ class Admin {
451
  <div class="editable">
452
  <p class="form-field form-field-wide">
453
  <?php if ( $invoice->exists() ) : ?>
454
- <p><textarea name="wcpdf_invoice_notes" cols="60" rows="5" disabled="disabled"><?php if (!empty($invoice_notes)) echo $invoice_notes; ?></textarea></p>
455
  <?php else : ?>
456
- <p><textarea name="wcpdf_invoice_notes" cols="60" rows="5" disabled="disabled"></textarea></p>
457
  <?php endif; ?>
458
  </p>
459
  </div>
460
  </p>
461
- </div>
 
462
  </div>
463
 
464
- <?php do_action( 'wpo_wcpdf_meta_box_after_document_notes', $invoice, $order ); ?>
465
 
466
  <?php
467
  }
@@ -525,72 +523,14 @@ class Admin {
525
  $post_type = get_post_type( $post_id );
526
  if( $post_type == 'shop_order' ) {
527
  // bail if this is not an actual 'Save order' action
528
- if (!isset($_POST['action']) || $_POST['action'] != 'editpost') {
529
  return;
530
  }
531
-
532
  $order = WCX::get_order( $post_id );
533
  if ( $invoice = wcpdf_get_invoice( $order ) ) {
534
- if ( !empty( $_POST['wcpdf_invoice_date'] ) ) {
535
- $date = $_POST['wcpdf_invoice_date'];
536
- $hour = !empty( $_POST['wcpdf_invoice_date_hour'] ) ? $_POST['wcpdf_invoice_date_hour'] : '00';
537
- $minute = !empty( $_POST['wcpdf_invoice_date_minute'] ) ? $_POST['wcpdf_invoice_date_minute'] : '00';
538
-
539
- // clean & sanitize input
540
- $date = date( 'Y-m-d', strtotime( $date ) );
541
- $hour = sprintf('%02d', intval( $hour ));
542
- $minute = sprintf('%02d', intval( $minute ) );
543
- $invoice_date = "{$date} {$hour}:{$minute}:00";
544
-
545
- // set date
546
- $invoice->set_date( $invoice_date );
547
- } elseif ( empty( $_POST['wcpdf_invoice_date'] ) && !empty( $_POST['_wcpdf_invoice_number'] ) ) {
548
- $invoice->set_date( current_time( 'timestamp', true ) );
549
- }
550
-
551
- if ( isset( $_POST['_wcpdf_invoice_number'] ) ) {
552
- // sanitize
553
- $invoice_number = sanitize_text_field( $_POST['_wcpdf_invoice_number'] );
554
- // set number
555
- $invoice->set_number( $invoice_number );
556
- }
557
-
558
- if ( isset( $_POST['wcpdf_invoice_notes'] ) ) {
559
- // allowed HTML
560
- $allowed_html = array(
561
- 'a' => array(
562
- 'href' => array(),
563
- 'title' => array(),
564
- 'id' => array(),
565
- 'class' => array(),
566
- 'style' => array(),
567
- ),
568
- 'br' => array(),
569
- 'em' => array(),
570
- 'strong'=> array(),
571
- 'div' => array(
572
- 'id' => array(),
573
- 'class' => array(),
574
- 'style' => array(),
575
- ),
576
- 'span' => array(
577
- 'id' => array(),
578
- 'class' => array(),
579
- 'style' => array(),
580
- ),
581
- 'p' => array(
582
- 'id' => array(),
583
- 'class' => array(),
584
- 'style' => array(),
585
- ),
586
- 'b' => array(),
587
- );
588
- // sanitize
589
- $invoice_notes = wp_kses( stripslashes($_POST['wcpdf_invoice_notes']), $allowed_html );
590
- // set notes
591
- $invoice->set_notes( $invoice_notes );
592
- }
593
-
594
  $invoice->save();
595
  }
596
  }
@@ -763,24 +703,37 @@ class Admin {
763
  'message' => 'nonce expired',
764
  ) );
765
  }
766
- if ( empty($_POST['order_id']) || empty($_POST['document']) ) {
 
 
 
 
 
 
 
767
  wp_send_json_error( array(
768
  'message' => 'incomplete request',
769
  ) );
770
  }
 
771
  if ( !current_user_can('manage_woocommerce') ) {
772
  wp_send_json_error( array(
773
  'message' => 'no permissions',
774
  ) );
775
  }
776
 
777
- $order_id = absint($_POST['order_id']);
778
- $document = sanitize_text_field($_POST['document']);
 
 
779
 
780
  try {
781
- $document = wcpdf_get_document( $document, wc_get_order( $order_id ) );
782
  if ( !empty($document) && $document->exists() ) {
783
- $document->regenerate();
 
 
 
784
  $response = array(
785
  'message' => $document->get_type()." regenerated",
786
  );
@@ -808,6 +761,66 @@ class Admin {
808
  $wp_admin_bar->add_node( $args );
809
  }
810
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
811
  }
812
 
813
  endif; // class_exists
272
  // Invoice number & date
273
  add_meta_box(
274
  'wpo_wcpdf-data-input-box',
275
+ __( 'PDF document data', 'woocommerce-pdf-invoices-packing-slips' ),
276
  array( $this, 'data_input_box_content' ),
277
  'shop_order',
278
  'normal',
375
  ?>
376
 
377
  <div class="wcpdf-data-fields" data-document="invoice" data-order_id="<?php echo WCX_Order::get_id( $order ); ?>">
378
+ <section class="wcpdf-data-fields-section number-date">
379
+ <h4>
380
+ <?php echo $invoice->get_title(); ?><?php if ($invoice->exists()) : ?>
381
+ <span class="wpo-wcpdf-edit-date-number dashicons dashicons-edit"></span>
382
+ <span class="wpo-wcpdf-delete-document dashicons dashicons-trash" data-nonce="<?php echo wp_create_nonce( "wpo_wcpdf_delete_document" ); ?>"></span>
383
+ <?php do_action( 'wpo_wcpdf_document_actions', $invoice ); ?>
384
+ <?php endif; ?>
385
+ </h4>
386
+
387
+ <!-- Read only -->
388
+ <div class="read-only">
389
+ <?php if ($invoice->exists()) : ?>
390
+ <div class="invoice-number">
391
+ <p class="form-field _wcpdf_invoice_number_field ">
392
+ <p>
393
+ <span><strong><?php _e( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</strong></span>
394
+ <span><?php if (!empty($invoice_number)) echo $invoice_number->get_formatted(); ?></span>
395
+ </p>
396
  </p>
397
+ </div>
 
398
 
399
+ <div class="invoice-date">
400
+ <p class="form-field form-field-wide">
401
+ <p>
402
+ <span><strong><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
403
+ <span><?php if (!empty($invoice_date)) echo $invoice_date->date_i18n( wc_date_format().' @ '.wc_time_format() ); ?></span>
404
+ </p>
405
  </p>
406
+ </div>
 
 
 
407
 
408
+ <?php do_action( 'wpo_wcpdf_meta_box_after_document_data', $invoice, $order ); ?>
 
 
 
409
 
 
 
 
 
 
 
410
  <?php else : ?>
411
+ <span class="wpo-wcpdf-set-date-number button"><?php _e( 'Set invoice number & date', 'woocommerce-pdf-invoices-packing-slips' ) ?></span>
412
  <?php endif; ?>
413
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
414
 
415
+ <!-- Editable -->
416
+ <div class="editable">
417
+ <p class="form-field _wcpdf_invoice_number_field ">
418
+ <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
419
+ <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
420
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>" disabled="disabled">
421
+ <?php else : ?>
422
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled">
423
+ <?php endif; ?>
424
+ </p>
425
+ <p class="form-field form-field-wide">
426
+ <label for="_wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
427
+ <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
428
+ <input type="text" class="date-picker-field" name="_wcpdf_invoice_date" id="_wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" disabled="disabled"/>@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="_wcpdf_invoice_date_hour" id="_wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="_wcpdf_invoice_date_minute" id="_wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
429
+ <?php else : ?>
430
+ <input type="text" class="date-picker-field" name="_wcpdf_invoice_date" id="_wcpdf_invoice_date" maxlength="10" disabled="disabled" value="<?php echo date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="_wcpdf_invoice_date_hour" id="_wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo date_i18n( 'H' ); ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="_wcpdf_invoice_date_minute" id="_wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
431
+ <?php endif; ?>
432
+ </p>
433
+ </div>
434
+ </section>
435
+ <?php do_action( 'wpo_wcpdf_meta_box_before_document_notes', $invoice, $order ); ?>
436
+ <section class="wcpdf-data-fields-section notes">
437
  <p class="form-field form-field-wide">
438
  <div>
439
  <span><strong><?php _e( 'Notes (printed in the invoice):', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
449
  <div class="editable">
450
  <p class="form-field form-field-wide">
451
  <?php if ( $invoice->exists() ) : ?>
452
+ <p><textarea name="_wcpdf_invoice_notes" cols="60" rows="5" disabled="disabled"><?php if (!empty($invoice_notes)) echo $invoice_notes; ?></textarea></p>
453
  <?php else : ?>
454
+ <p><textarea name="_wcpdf_invoice_notes" cols="60" rows="5" disabled="disabled"></textarea></p>
455
  <?php endif; ?>
456
  </p>
457
  </div>
458
  </p>
459
+ </section>
460
+ <?php do_action( 'wpo_wcpdf_meta_box_after_document_notes', $invoice, $order ); ?>
461
  </div>
462
 
 
463
 
464
  <?php
465
  }
523
  $post_type = get_post_type( $post_id );
524
  if( $post_type == 'shop_order' ) {
525
  // bail if this is not an actual 'Save order' action
526
+ if ( ! isset($_POST['action']) || $_POST['action'] != 'editpost' ) {
527
  return;
528
  }
529
+
530
  $order = WCX::get_order( $post_id );
531
  if ( $invoice = wcpdf_get_invoice( $order ) ) {
532
+ $document_data = $this->process_order_document_form_data( $_POST, $invoice->slug );
533
+ $invoice->set_data( $document_data, $order );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  $invoice->save();
535
  }
536
  }
703
  'message' => 'nonce expired',
704
  ) );
705
  }
706
+
707
+ if ( ! isset($_POST['action']) || $_POST['action'] != 'wpo_wcpdf_regenerate_document' ) {
708
+ wp_send_json_error( array(
709
+ 'message' => 'bad action',
710
+ ) );
711
+ }
712
+
713
+ if( empty($_POST['form_data']) || empty($_POST['order_id']) || empty($_POST['document_type']) ) {
714
  wp_send_json_error( array(
715
  'message' => 'incomplete request',
716
  ) );
717
  }
718
+
719
  if ( !current_user_can('manage_woocommerce') ) {
720
  wp_send_json_error( array(
721
  'message' => 'no permissions',
722
  ) );
723
  }
724
 
725
+ $order_id = absint( $_POST['order_id'] );
726
+ $order = WCX::get_order( $order_id );
727
+ $document_type = sanitize_text_field( $_POST['document_type'] );
728
+ $form_data = json_decode( stripslashes( $_POST['form_data'] ), true );
729
 
730
  try {
731
+ $document = wcpdf_get_document( $document_type, wc_get_order( $order_id ) );
732
  if ( !empty($document) && $document->exists() ) {
733
+ // save document data
734
+ $document_data = $this->process_order_document_form_data( $form_data, $document->slug );
735
+ $document->regenerate( $order, $document_data );
736
+
737
  $response = array(
738
  'message' => $document->get_type()." regenerated",
739
  );
761
  $wp_admin_bar->add_node( $args );
762
  }
763
  }
764
+
765
+ public function process_order_document_form_data( $form_data, $document_slug )
766
+ {
767
+ $data = array();
768
+
769
+ if( isset( $form_data['_wcpdf_'.$document_slug.'_number'] ) ) {
770
+ $data['number'] = sanitize_text_field( $form_data['_wcpdf_'.$document_slug.'_number'] );
771
+ }
772
+
773
+ if( ! empty( $form_data['_wcpdf_'.$document_slug.'_date'] ) ) {
774
+ $date = $form_data['_wcpdf_'.$document_slug.'_date'];
775
+ $hour = ! empty( $form_data['_wcpdf_'.$document_slug.'_date_hour'] ) ? $form_data['_wcpdf_'.$document_slug.'_date_hour'] : '00';
776
+ $minute = ! empty( $form_data['_wcpdf_'.$document_slug.'_date_minute'] ) ? $form_data['_wcpdf_'.$document_slug.'_date_minute'] : '00';
777
+
778
+ // clean & sanitize input
779
+ $date = date( 'Y-m-d', strtotime( $date ) );
780
+ $hour = sprintf('%02d', intval( $hour ));
781
+ $minute = sprintf('%02d', intval( $minute ) );
782
+ $data['date'] = "{$date} {$hour}:{$minute}:00";
783
+
784
+ } elseif ( empty( $_POST['_wcpdf_'.$document_slug.'_date'] ) && !empty( $_POST['_wcpdf_'.$document_slug.'_number'] ) ) {
785
+ $data['date'] = current_time( 'timestamp', true );
786
+ }
787
+
788
+ if ( isset( $form_data['_wcpdf_'.$document_slug.'_notes'] ) ) {
789
+ // allowed HTML
790
+ $allowed_html = array(
791
+ 'a' => array(
792
+ 'href' => array(),
793
+ 'title' => array(),
794
+ 'id' => array(),
795
+ 'class' => array(),
796
+ 'style' => array(),
797
+ ),
798
+ 'br' => array(),
799
+ 'em' => array(),
800
+ 'strong'=> array(),
801
+ 'div' => array(
802
+ 'id' => array(),
803
+ 'class' => array(),
804
+ 'style' => array(),
805
+ ),
806
+ 'span' => array(
807
+ 'id' => array(),
808
+ 'class' => array(),
809
+ 'style' => array(),
810
+ ),
811
+ 'p' => array(
812
+ 'id' => array(),
813
+ 'class' => array(),
814
+ 'style' => array(),
815
+ ),
816
+ 'b' => array(),
817
+ );
818
+ // sanitize
819
+ $data['notes'] = wp_kses( stripslashes($form_data['_wcpdf_'.$document_slug.'_notes']), $allowed_html );
820
+ }
821
+
822
+ return $data;
823
+ }
824
  }
825
 
826
  endif; // class_exists
includes/class-wcpdf-install.php CHANGED
@@ -76,7 +76,7 @@ class Install {
76
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
77
 
78
  // check if tmp folder exists => if not, initialize
79
- if ( $tmp_base !== false && !@is_dir( $tmp_base ) ) {
80
  WPO_WCPDF()->main->init_tmp();
81
  }
82
 
@@ -193,11 +193,13 @@ class Install {
193
  // sync fonts on every upgrade!
194
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
195
 
 
 
 
196
  // check if tmp folder exists => if not, initialize
197
- if ( $tmp_base !== false && !@is_dir( $tmp_base ) ) {
198
  WPO_WCPDF()->main->init_tmp();
199
  } else {
200
- $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
201
  // don't try merging fonts with local when updating pre 2.0
202
  $pre_2 = ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) );
203
  $merge_with_local = $pre_2 ? false : true;
@@ -357,16 +359,18 @@ class Install {
357
  // make sure fonts match with version: copy from plugin folder
358
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
359
 
 
 
 
360
  // don't continue if we don't have an upload dir
361
  if ($tmp_base === false) {
362
  return false;
363
  }
364
 
365
  // check if tmp folder exists => if not, initialize
366
- if ( !@is_dir( $tmp_base ) ) {
367
  WPO_WCPDF()->main->init_tmp();
368
  } else {
369
- $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
370
  WPO_WCPDF()->main->copy_fonts( $font_path );
371
  }
372
  }
76
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
77
 
78
  // check if tmp folder exists => if not, initialize
79
+ if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) ) {
80
  WPO_WCPDF()->main->init_tmp();
81
  }
82
 
193
  // sync fonts on every upgrade!
194
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
195
 
196
+ // get fonts folder path
197
+ $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
198
+
199
  // check if tmp folder exists => if not, initialize
200
+ if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) || ! @is_dir( $font_path ) || ! wp_is_writable( $font_path ) ) {
201
  WPO_WCPDF()->main->init_tmp();
202
  } else {
 
203
  // don't try merging fonts with local when updating pre 2.0
204
  $pre_2 = ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) );
205
  $merge_with_local = $pre_2 ? false : true;
359
  // make sure fonts match with version: copy from plugin folder
360
  $tmp_base = WPO_WCPDF()->main->get_tmp_base();
361
 
362
+ // make sure we have the fonts directory
363
+ $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
364
+
365
  // don't continue if we don't have an upload dir
366
  if ($tmp_base === false) {
367
  return false;
368
  }
369
 
370
  // check if tmp folder exists => if not, initialize
371
+ if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) || ! @is_dir( $font_path ) || ! wp_is_writable( $font_path ) ) {
372
  WPO_WCPDF()->main->init_tmp();
373
  } else {
 
374
  WPO_WCPDF()->main->copy_fonts( $font_path );
375
  }
376
  }
includes/class-wcpdf-main.php CHANGED
@@ -13,6 +13,8 @@ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Main' ) ) :
13
 
14
  class Main {
15
 
 
 
16
  function __construct() {
17
  add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
18
  add_action( 'wp_ajax_nopriv_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
@@ -53,6 +55,17 @@ class Main {
53
 
54
  // apply header logo height
55
  add_action( 'wpo_wcpdf_custom_styles', array( $this, 'set_header_logo_height' ), 9, 2 );
 
 
 
 
 
 
 
 
 
 
 
56
  }
57
 
58
  /**
@@ -93,6 +106,9 @@ class Main {
93
  }
94
 
95
  $tmp_path = $this->get_tmp_path('attachments');
 
 
 
96
 
97
  // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
98
  // array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
@@ -373,7 +389,7 @@ class Main {
373
  }
374
 
375
  // check if tmp folder exists => if not, initialize
376
- if ( !@is_dir( $tmp_base ) ) {
377
  $this->init_tmp();
378
  }
379
 
@@ -398,11 +414,21 @@ class Main {
398
  }
399
 
400
  // double check for existence, in case tmp_base was installed, but subfolder not created
401
- if ( !@is_dir( $tmp_path ) ) {
402
- @mkdir( $tmp_path );
 
 
 
 
 
 
 
 
 
 
403
  }
404
 
405
- return $tmp_path;
406
  }
407
 
408
  /**
@@ -489,18 +515,37 @@ class Main {
489
  $tmp_base = $this->get_tmp_base();
490
 
491
  // create plugin base temp folder
492
- mkdir( $tmp_base );
 
493
 
494
- if (!is_dir($tmp_base)) {
495
- wcpdf_log_error( "Unable to create temp folder {$tmp_base}", 'critical' );
 
 
 
 
 
 
 
 
496
  }
497
 
498
  // create subfolders & protect
499
- $subfolders = array( 'attachments', 'fonts', 'dompdf' );
500
- foreach ( $subfolders as $subfolder ) {
501
  $path = $tmp_base . $subfolder . '/';
502
- if ( !is_dir( $path ) ) {
503
- mkdir( $path );
 
 
 
 
 
 
 
 
 
 
 
504
  }
505
 
506
  // copy font files
@@ -514,13 +559,48 @@ class Main {
514
  }
515
  }
516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  /**
518
  * Copy contents from one directory to another
519
  */
520
  public function copy_directory ( $old_path, $new_path ) {
521
  if( empty($old_path) || empty($new_path) ) return;
522
  if( ! is_dir($old_path) ) return;
523
- if( ! is_dir($new_path) ) mkdir($new_path);
 
 
 
 
 
 
 
 
 
 
 
 
 
524
 
525
  global $wp_filesystem;
526
 
@@ -542,6 +622,28 @@ class Main {
542
  }
543
  }
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  /**
546
  * Copy DOMPDF fonts to wordpress tmp folder
547
  */
13
 
14
  class Main {
15
 
16
+ private $subfolders = array( 'attachments', 'fonts', 'dompdf' );
17
+
18
  function __construct() {
19
  add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
20
  add_action( 'wp_ajax_nopriv_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
55
 
56
  // apply header logo height
57
  add_action( 'wpo_wcpdf_custom_styles', array( $this, 'set_header_logo_height' ), 9, 2 );
58
+
59
+ // show notices of missing required directories
60
+ if( get_option( 'wpo_wcpdf_no_dir_error' ) ) {
61
+ // if all folders exist and are writable delete the option
62
+ if( $this->tmp_folders_exist_and_writable() ) {
63
+ delete_option( 'wpo_wcpdf_no_dir_error' );
64
+ // if not, show notice
65
+ } else {
66
+ add_action( 'admin_notices', array( $this, 'no_dir_notice' ), 1 );
67
+ }
68
+ }
69
  }
70
 
71
  /**
106
  }
107
 
108
  $tmp_path = $this->get_tmp_path('attachments');
109
+ if ( ! @is_dir( $tmp_path ) || ! wp_is_writable( $tmp_path ) ) {
110
+ return $attachments;
111
+ }
112
 
113
  // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
114
  // array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
389
  }
390
 
391
  // check if tmp folder exists => if not, initialize
392
+ if ( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) ) {
393
  $this->init_tmp();
394
  }
395
 
414
  }
415
 
416
  // double check for existence, in case tmp_base was installed, but subfolder not created
417
+ if ( ! is_dir( $tmp_path ) ) {
418
+ $dir = mkdir( $tmp_path );
419
+
420
+ if ( ! $dir ) {
421
+ update_option( 'wpo_wcpdf_no_dir_error', $tmp_path );
422
+ wcpdf_log_error( "Unable to create folder {$tmp_path}", 'critical' );
423
+ return false;
424
+ }
425
+ } elseif( ! wp_is_writable( $tmp_path ) ) {
426
+ update_option( 'wpo_wcpdf_no_dir_error', $tmp_path );
427
+ wcpdf_log_error( "Temp folder {$tmp_path} not writable", 'critical' );
428
+ return false;
429
  }
430
 
431
+ return apply_filters( 'wpo_wcpdf_tmp_path_{$type}', $tmp_path );;
432
  }
433
 
434
  /**
515
  $tmp_base = $this->get_tmp_base();
516
 
517
  // create plugin base temp folder
518
+ if ( ! is_dir( $tmp_base ) ) {
519
+ $dir = mkdir( $tmp_base );
520
 
521
+ // don't continue if we don't have an upload dir
522
+ if ( ! $dir ) {
523
+ update_option( 'wpo_wcpdf_no_dir_error', $tmp_base );
524
+ wcpdf_log_error( "Unable to create temp folder {$tmp_base}", 'critical' );
525
+ return false;
526
+ }
527
+ } elseif( ! wp_is_writable( $tmp_base ) ) {
528
+ update_option( 'wpo_wcpdf_no_dir_error', $tmp_base );
529
+ wcpdf_log_error( "Temp folder {$tmp_base} not writable", 'critical' );
530
+ return false;
531
  }
532
 
533
  // create subfolders & protect
534
+ foreach ( $this->subfolders as $subfolder ) {
 
535
  $path = $tmp_base . $subfolder . '/';
536
+ if ( ! is_dir( $path ) ) {
537
+ $dir = mkdir( $path );
538
+
539
+ // check if we have dir
540
+ if ( ! $dir ) {
541
+ update_option( 'wpo_wcpdf_no_dir_error', $path );
542
+ wcpdf_log_error( "Unable to create folder {$path}", 'critical' );
543
+ return false;
544
+ }
545
+ } elseif( ! wp_is_writable( $path ) ) {
546
+ update_option( 'wpo_wcpdf_no_dir_error', $path );
547
+ wcpdf_log_error( "Temp folder {$path} not writable", 'critical' );
548
+ return false;
549
  }
550
 
551
  // copy font files
559
  }
560
  }
561
 
562
+ public function no_dir_notice() {
563
+ $path = get_option( 'wpo_wcpdf_no_dir_error' );
564
+ if ( $path ) {
565
+ ob_start();
566
+ ?>
567
+ <div class="error">
568
+ <p><?php printf( __( "The %s directory %s couldn't be created or is not writable!", 'woocommerce-pdf-invoices-packing-slips' ), '<strong>WooCommerce PDF Invoices & Packing Slips</strong>' ,'<code>' . $path . '</code>' ); ?></p>
569
+ <p><?php _e( 'Please check your directories write permissions or contact your hosting service provider.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
570
+ <p><a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_hide_no_dir_notice', 'true' ) ); ?>"><?php _e( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
571
+ </div>
572
+ <?php
573
+ echo ob_get_clean();
574
+
575
+ // save option to hide notice
576
+ if ( isset( $_GET['wpo_wcpdf_hide_no_dir_notice'] ) ) {
577
+ delete_option( 'wpo_wcpdf_no_dir_error', true );
578
+ wp_redirect( 'admin.php?page=wpo_wcpdf_options_page' );
579
+ exit;
580
+ }
581
+ }
582
+ }
583
+
584
  /**
585
  * Copy contents from one directory to another
586
  */
587
  public function copy_directory ( $old_path, $new_path ) {
588
  if( empty($old_path) || empty($new_path) ) return;
589
  if( ! is_dir($old_path) ) return;
590
+ if( ! is_dir($new_path) ) {
591
+ $dir = mkdir($new_path);
592
+
593
+ // check if we have dir
594
+ if ( ! $dir ) {
595
+ update_option( 'wpo_wcpdf_no_dir_error', $new_path );
596
+ wcpdf_log_error( "Unable to create folder {$new_path}", 'critical' );
597
+ return false;
598
+ }
599
+ } elseif( ! wp_is_writable( $new_path ) ) {
600
+ update_option( 'wpo_wcpdf_no_dir_error', $new_path );
601
+ wcpdf_log_error( "Temp folder {$new_path} not writable", 'critical' );
602
+ return false;
603
+ }
604
 
605
  global $wp_filesystem;
606
 
622
  }
623
  }
624
 
625
+ /**
626
+ * checks if the plugin tmp folders exist and are writable
627
+ */
628
+ private function tmp_folders_exist_and_writable()
629
+ {
630
+ // tmp base
631
+ $tmp_base = $this->get_tmp_base();
632
+ if( ! @is_dir( $tmp_base ) || ! wp_is_writable( $tmp_base ) ) {
633
+ return false;
634
+ }
635
+
636
+ // subfolders
637
+ foreach( $this->subfolders as $type ) {
638
+ $tmp_path = $this->get_tmp_path( $type );
639
+ if( ! @is_dir( $tmp_path ) || ! wp_is_writable( $tmp_base ) ) {
640
+ return false;
641
+ }
642
+ }
643
+
644
+ return true;
645
+ }
646
+
647
  /**
648
  * Copy DOMPDF fonts to wordpress tmp folder
649
  */
includes/compatibility/class-wc-order-compatibility.php CHANGED
@@ -1,412 +1,412 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices\Compatibility;
3
-
4
- /**
5
- * Derived from SkyVerge WooCommerce Plugin Framework https://github.com/skyverge/wc-plugin-framework/
6
- */
7
-
8
- defined( 'ABSPATH' ) or exit;
9
-
10
- if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Compatibility\\Order' ) ) :
11
-
12
- /**
13
- * WooCommerce order compatibility class.
14
- *
15
- * @since 4.6.0-dev
16
- */
17
- class Order extends Data {
18
-
19
-
20
- /** @var array mapped compatibility properties, as `$new_prop => $old_prop` */
21
- protected static $compat_props = array(
22
- 'date_completed' => 'completed_date',
23
- 'date_paid' => 'paid_date',
24
- 'date_modified' => 'modified_date',
25
- 'date_created' => 'order_date',
26
- 'customer_id' => 'customer_user',
27
- 'discount' => 'cart_discount',
28
- 'discount_tax' => 'cart_discount_tax',
29
- 'shipping_total' => 'total_shipping',
30
- 'type' => 'order_type',
31
- 'currency' => 'order_currency',
32
- 'version' => 'order_version',
33
- );
34
-
35
-
36
- /**
37
- * Backports WC_Order::get_id() method to pre-2.6.0
38
- *
39
- * @since 4.2.0
40
- * @param \WC_Order $order order object
41
- * @return string|int order ID
42
- */
43
- public static function get_id( $order ) {
44
-
45
- if ( method_exists( $order, 'get_id' ) ) {
46
-
47
- return $order->get_id();
48
-
49
- } else {
50
-
51
- return isset($order->id) ? $order->id : false;
52
- }
53
- }
54
-
55
-
56
- /**
57
- * Gets an order property.
58
- *
59
- * @since 4.6.0-dev
60
- * @param \WC_Order $object the order object
61
- * @param string $prop the property name
62
- * @param string $context if 'view' then the value will be filtered
63
- * @return mixed
64
- */
65
- public static function get_prop( $object, $prop, $context = 'edit', $compat_props = array() ) {
66
-
67
- // backport a few specific properties to pre-3.0
68
- if ( WC_Core::is_wc_version_lt_3_0() ) {
69
-
70
- // converge the shipping total prop for the raw context
71
- if ( 'shipping_total' === $prop && 'view' !== $context ) {
72
-
73
- $prop = 'order_shipping';
74
-
75
- // get the post_parent and bail early
76
- } elseif ( 'parent_id' === $prop ) {
77
-
78
- return $object->post->post_parent;
79
- }
80
- }
81
-
82
- $value = parent::get_prop( $object, $prop, $context, self::$compat_props );
83
-
84
- // 3.0+ date getters return a DateTime object, where previously MySQL date strings were returned
85
- if ( WC_Core::is_wc_version_lt_3_0() && in_array( $prop, array( 'date_completed', 'date_paid', 'date_modified', 'date_created' ), true ) ) {
86
- // parent fallback for empty date values in refunds
87
- if ( empty( $value ) && $object->order_type == 'refund' ) {
88
- $parent_order_id = wp_get_post_parent_id( $object->id );
89
- $parent_order = wc_get_order( $parent_order_id );
90
- $value = parent::get_prop( $parent_order, $prop, $context, self::$compat_props );
91
- }
92
-
93
- // abort mission if still empty
94
- if ( empty( $value ) ) {
95
- return $value;
96
- }
97
-
98
- if ( is_numeric( $value ) ) { // incidental for WC2.7 orders
99
- $value = new WC_DateTime( "@{$value}", new \DateTimeZone( 'UTC' ) );
100
- $value->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
101
- } else {
102
- // Strings are defined in local WP timezone. Convert to UTC.
103
- if ( 1 === preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|((-|\+)\d{2}:\d{2}))$/', $value, $date_bits ) ) {
104
- $offset = ! empty( $date_bits[7] ) ? iso8601_timezone_to_offset( $date_bits[7] ) : wc_timezone_offset();
105
- $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ) - $offset;
106
- } else {
107
- $timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $value ) ) ) );
108
- }
109
- $value = new WC_DateTime( "@{$timestamp}", new \DateTimeZone( 'UTC' ) );
110
- }
111
-
112
- // Set local timezone or offset.
113
- if ( get_option( 'timezone_string' ) ) {
114
- $value->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
115
- } else {
116
- $value->set_utc_offset( wc_timezone_offset() );
117
- }
118
- }
119
-
120
- return $value;
121
- }
122
-
123
-
124
- /**
125
- * Sets an order's properties.
126
- *
127
- * Note that this does not save any data to the database.
128
- *
129
- * @since 4.6.0-dev
130
- * @param \WC_Order $object the order object
131
- * @param array $props the new properties as $key => $value
132
- * @return \WC_Order
133
- */
134
- public static function set_props( $object, $props, $compat_props = array() ) {
135
-
136
- return parent::set_props( $object, $props, self::$compat_props );
137
- }
138
-
139
- /**
140
- * Backports WC_Order::set_address_prop() to pre-3.0
141
- * Saves by default.
142
- *
143
- * @since 4.6.0-dev
144
- * @param \WC_Order $order the order object
145
- * @param string $prop Name of prop to set.
146
- * @param string $address Name of address to set. billing or shipping.
147
- * @param mixed $value Value of the prop.
148
- * @param bool $save whether to save the order/property
149
- * @return \WC_Order
150
- */
151
- public static function set_address_prop( \WC_Order $order, $prop, $address = 'billing', $value, $save = true ) {
152
- if ( WC_Core::is_wc_version_gte_3_0() ) {
153
- if ( is_callable( array( $order, "set_{$address}_{$prop}" ) ) ) {
154
- $order->{"set_{$address}_{$prop}"}( $value );
155
- if ($save === true) {
156
- $order->save();
157
- }
158
- }
159
- } else {
160
- // wc 2.6 or older
161
- if ($save === true) {
162
- // store directly in postmeta
163
- update_post_meta( $order->id, "_{$address}_{$prop}", $value );
164
- } else {
165
- // only change property in the order
166
- $order->$prop = $value;
167
- }
168
- }
169
-
170
- return $order;
171
- }
172
-
173
- /**
174
- * Implements WC_Order::get_item_meta for 3.0+
175
- * @param \WC_Order $order the order object
176
- * @param int $item_id the item id
177
- * @param int $key the meta key
178
- * @param boolean $single single or multiple
179
- * @return mixed item meta
180
- */
181
- public static function get_item_meta( $object, $item_id, $key = '', $single = false ) {
182
- if (function_exists('wc_get_order_item_meta')) {
183
- $item_meta = wc_get_order_item_meta( $item_id, $key, $single );
184
- } else {
185
- $item_meta = $object->get_item_meta( $item_id, $key, $single );
186
- }
187
- return $item_meta;
188
- }
189
-
190
- /**
191
- * Backports WC_Order::get_status() to pre-3.0.0
192
- *
193
- * @since 4.6.0-dev
194
- * @param \WC_Order $order the order object
195
- * @return string order status
196
- */
197
- public static function get_status( \WC_Order $order ) {
198
-
199
- if ( method_exists( $order, 'get_status' ) ) {
200
- return $order->get_status();
201
- } else {
202
- return $order->status;
203
- }
204
- }
205
-
206
- /**
207
- * Order item CRUD compatibility method to add a coupon to an order.
208
- *
209
- * @since 4.6.0-dev
210
- * @param \WC_Order $order the order object
211
- * @param array $code the coupon code
212
- * @param int $discount the discount amount.
213
- * @param int $discount_tax the discount tax amount.
214
- * @return int the order item ID
215
- */
216
- public static function add_coupon( \WC_Order $order, $code = array(), $discount = 0, $discount_tax = 0 ) {
217
-
218
- if ( WC_Core::is_wc_version_gte_3_0() ) {
219
-
220
- $item = new \WC_Order_Item_Coupon();
221
-
222
- $item->set_props( array(
223
- 'code' => $code,
224
- 'discount' => $discount,
225
- 'discount_tax' => $discount_tax,
226
- 'order_id' => $order->get_id(),
227
- ) );
228
-
229
- $item->save();
230
-
231
- $order->add_item( $item );
232
-
233
- return $item->get_id();
234
-
235
- } else {
236
-
237
- return $order->add_coupon( $code, $discount, $discount_tax );
238
- }
239
- }
240
-
241
-
242
- /**
243
- * Order item CRUD compatibility method to add a fee to an order.
244
- *
245
- * @since 4.6.0-dev
246
- * @param \WC_Order $order the order object
247
- * @param object $fee the fee to add
248
- * @return int|\WC_Order_Item the order item ID
249
- */
250
- public static function add_fee( \WC_Order $order, $fee ) {
251
-
252
- if ( WC_Core::is_wc_version_gte_3_0() ) {
253
-
254
- $item = new \WC_Order_Item_Fee();
255
-
256
- $item->set_props( array(
257
- 'name' => $fee->name,
258
- 'tax_class' => $fee->taxable ? $fee->tax_class : 0,
259
- 'total' => $fee->amount,
260
- 'total_tax' => $fee->tax,
261
- 'taxes' => array(
262
- 'total' => $fee->tax_data,
263
- ),
264
- 'order_id' => $order->get_id(),
265
- ) );
266
-
267
- $item->save();
268
-
269
- $order->add_item( $item );
270
-
271
- return $item->get_id();
272
-
273
- } else {
274
-
275
- return $order->add_fee( $fee );
276
- }
277
- }
278
-
279
-
280
- /**
281
- * Order item CRUD compatibility method to update an order coupon.
282
- *
283
- * @since 4.6.0-dev
284
- * @param \WC_Order $order the order object
285
- * @param int|\WC_Order_Item $item the order item ID
286
- * @param array $args {
287
- * The coupon item args.
288
- *
289
- * @type string $code the coupon code
290
- * @type float $discount the coupon discount amount
291
- * @type float $discount_tax the coupon discount tax amount
292
- * }
293
- * @return int|bool the order item ID or false on failure
294
- */
295
- public static function update_coupon( \WC_Order $order, $item, $args ) {
296
-
297
- if ( WC_Core::is_wc_version_gte_3_0() ) {
298
-
299
- if ( is_numeric( $item ) ) {
300
- $item = $order->get_item( $item );
301
- }
302
-
303
- if ( ! is_object( $item ) || ! $item->is_type( 'coupon' ) ) {
304
- return false;
305
- }
306
-
307
- if ( ! $order->get_id() ) {
308
- $order->save();
309
- }
310
-
311
- $item->set_order_id( $order->get_id() );
312
- $item->set_props( $args );
313
- $item->save();
314
-
315
- return $item->get_id();
316
-
317
- } else {
318
-
319
- // convert 3.0+ args for backwards compatibility
320
- if ( isset( $args['discount'] ) ) {
321
- $args['discount_amount'] = $args['discount'];
322
- }
323
- if ( isset( $args['discount_tax'] ) ) {
324
- $args['discount_amount_tax'] = $args['discount_tax'];
325
- }
326
-
327
- return $order->update_coupon( $item, $args );
328
- }
329
- }
330
-
331
-
332
- /**
333
- * Order item CRUD compatibility method to update an order fee.
334
- *
335
- * @since 4.6.0-dev
336
- * @param \WC_Order $order the order object
337
- * @param int $item the order item ID
338
- * @param array $args {
339
- * The fee item args.
340
- *
341
- * @type string $name the fee name
342
- * @type string $tax_class the fee's tax class
343
- * @type float $line_total the fee total amount
344
- * @type float $line_tax the fee tax amount
345
- * }
346
- * @return int|bool the order item ID or false on failure
347
- */
348
- public static function update_fee( \WC_Order $order, $item, $args ) {
349
-
350
- if ( WC_Core::is_wc_version_gte_3_0() ) {
351
-
352
- if ( is_numeric( $item ) ) {
353
- $item = $order->get_item( $item );
354
- }
355
-
356
- if ( ! is_object( $item ) || ! $item->is_type( 'fee' ) ) {
357
- return false;
358
- }
359
-
360
- if ( ! $order->get_id() ) {
361
- $order->save();
362
- }
363
-
364
- $item->set_order_id( $order->get_id() );
365
- $item->set_props( $args );
366
- $item->save();
367
-
368
- return $item->get_id();
369
-
370
- } else {
371
-
372
- return $order->update_fee( $item, $args );
373
- }
374
- }
375
-
376
-
377
- /**
378
- * Backports wc_reduce_stock_levels() to pre-3.0.0
379
- *
380
- * @since 4.6.0-dev
381
- * @param \WC_Order $order the order object
382
- */
383
- public static function reduce_stock_levels( \WC_Order $order ) {
384
-
385
- if ( WC_Core::is_wc_version_gte_3_0() ) {
386
- wc_reduce_stock_levels( $order->get_id() );
387
- } else {
388
- $order->reduce_order_stock();
389
- }
390
- }
391
-
392
-
393
- /**
394
- * Backports wc_update_total_sales_counts() to pre-3.0.0
395
- *
396
- * @since 4.6.0-dev
397
- * @param \WC_Order $order the order object
398
- */
399
- public static function update_total_sales_counts( \WC_Order $order ) {
400
-
401
- if ( WC_Core::is_wc_version_gte_3_0() ) {
402
- wc_update_total_sales_counts( $order->get_id() );
403
- } else {
404
- $order->record_product_sales();
405
- }
406
- }
407
-
408
-
409
- }
410
-
411
-
412
- endif; // Class exists check
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices\Compatibility;
3
+
4
+ /**
5
+ * Derived from SkyVerge WooCommerce Plugin Framework https://github.com/skyverge/wc-plugin-framework/
6
+ */
7
+
8
+ defined( 'ABSPATH' ) or exit;
9
+
10
+ if ( ! class_exists( '\\WPO\\WC\\PDF_Invoices\\Compatibility\\Order' ) ) :
11
+
12
+ /**
13
+ * WooCommerce order compatibility class.
14
+ *
15
+ * @since 4.6.0-dev
16
+ */
17
+ class Order extends Data {
18
+
19
+
20
+ /** @var array mapped compatibility properties, as `$new_prop => $old_prop` */
21
+ protected static $compat_props = array(
22
+ 'date_completed' => 'completed_date',
23
+ 'date_paid' => 'paid_date',
24
+ 'date_modified' => 'modified_date',
25
+ 'date_created' => 'order_date',
26
+ 'customer_id' => 'customer_user',
27
+ 'discount' => 'cart_discount',
28
+ 'discount_tax' => 'cart_discount_tax',
29
+ 'shipping_total' => 'total_shipping',
30
+ 'type' => 'order_type',
31
+ 'currency' => 'order_currency',
32
+ 'version' => 'order_version',
33
+ );
34
+
35
+
36
+ /**
37
+ * Backports WC_Order::get_id() method to pre-2.6.0
38
+ *
39
+ * @since 4.2.0
40
+ * @param \WC_Order $order order object
41
+ * @return string|int order ID
42
+ */
43
+ public static function get_id( $order ) {
44
+
45
+ if ( method_exists( $order, 'get_id' ) ) {
46
+
47
+ return $order->get_id();
48
+
49
+ } else {
50
+
51
+ return isset($order->id) ? $order->id : false;
52
+ }
53
+ }
54
+
55
+
56
+ /**
57
+ * Gets an order property.
58
+ *
59
+ * @since 4.6.0-dev
60
+ * @param \WC_Order $object the order object
61
+ * @param string $prop the property name
62
+ * @param string $context if 'view' then the value will be filtered
63
+ * @return mixed
64
+ */
65
+ public static function get_prop( $object, $prop, $context = 'edit', $compat_props = array() ) {
66
+
67
+ // backport a few specific properties to pre-3.0
68
+ if ( WC_Core::is_wc_version_lt_3_0() ) {
69
+
70
+ // converge the shipping total prop for the raw context
71
+ if ( 'shipping_total' === $prop && 'view' !== $context ) {
72
+
73
+ $prop = 'order_shipping';
74
+
75
+ // get the post_parent and bail early
76
+ } elseif ( 'parent_id' === $prop ) {
77
+
78
+ return $object->post->post_parent;
79
+ }
80
+ }
81
+
82
+ $value = parent::get_prop( $object, $prop, $context, self::$compat_props );
83
+
84
+ // 3.0+ date getters return a DateTime object, where previously MySQL date strings were returned
85
+ if ( WC_Core::is_wc_version_lt_3_0() && in_array( $prop, array( 'date_completed', 'date_paid', 'date_modified', 'date_created' ), true ) ) {
86
+ // parent fallback for empty date values in refunds
87
+ if ( empty( $value ) && $object->order_type == 'refund' ) {
88
+ $parent_order_id = wp_get_post_parent_id( $object->id );
89
+ $parent_order = wc_get_order( $parent_order_id );
90
+ $value = parent::get_prop( $parent_order, $prop, $context, self::$compat_props );
91
+ }
92
+
93
+ // abort mission if still empty
94
+ if ( empty( $value ) ) {
95
+ return $value;
96
+ }
97
+
98
+ if ( is_numeric( $value ) ) { // incidental for WC2.7 orders
99
+ $value = new WC_DateTime( "@{$value}", new \DateTimeZone( 'UTC' ) );
100
+ $value->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
101
+ } else {
102
+ // Strings are defined in local WP timezone. Convert to UTC.
103
+ if ( 1 === preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|((-|\+)\d{2}:\d{2}))$/', $value, $date_bits ) ) {
104
+ $offset = ! empty( $date_bits[7] ) ? iso8601_timezone_to_offset( $date_bits[7] ) : wc_timezone_offset();
105
+ $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ) - $offset;
106
+ } else {
107
+ $timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $value ) ) ) );
108
+ }
109
+ $value = new WC_DateTime( "@{$timestamp}", new \DateTimeZone( 'UTC' ) );
110
+ }
111
+
112
+ // Set local timezone or offset.
113
+ if ( get_option( 'timezone_string' ) ) {
114
+ $value->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
115
+ } else {
116
+ $value->set_utc_offset( wc_timezone_offset() );
117
+ }
118
+ }
119
+
120
+ return $value;
121
+ }
122
+
123
+
124
+ /**
125
+ * Sets an order's properties.
126
+ *
127
+ * Note that this does not save any data to the database.
128
+ *
129
+ * @since 4.6.0-dev
130
+ * @param \WC_Order $object the order object
131
+ * @param array $props the new properties as $key => $value
132
+ * @return \WC_Order
133
+ */
134
+ public static function set_props( $object, $props, $compat_props = array() ) {
135
+
136
+ return parent::set_props( $object, $props, self::$compat_props );
137
+ }
138
+
139
+ /**
140
+ * Backports WC_Order::set_address_prop() to pre-3.0
141
+ * Saves by default.
142
+ *
143
+ * @since 4.6.0-dev
144
+ * @param \WC_Order $order the order object
145
+ * @param string $prop Name of prop to set.
146
+ * @param string $address Name of address to set. billing or shipping.
147
+ * @param mixed $value Value of the prop.
148
+ * @param bool $save whether to save the order/property
149
+ * @return \WC_Order
150
+ */
151
+ public static function set_address_prop( \WC_Order $order, $prop, $address = 'billing', $value = null, $save = true ) {
152
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
153
+ if ( is_callable( array( $order, "set_{$address}_{$prop}" ) ) ) {
154
+ $order->{"set_{$address}_{$prop}"}( $value );
155
+ if ($save === true) {
156
+ $order->save();
157
+ }
158
+ }
159
+ } else {
160
+ // wc 2.6 or older
161
+ if ($save === true) {
162
+ // store directly in postmeta
163
+ update_post_meta( $order->id, "_{$address}_{$prop}", $value );
164
+ } else {
165
+ // only change property in the order
166
+ $order->$prop = $value;
167
+ }
168
+ }
169
+
170
+ return $order;
171
+ }
172
+
173
+ /**
174
+ * Implements WC_Order::get_item_meta for 3.0+
175
+ * @param \WC_Order $order the order object
176
+ * @param int $item_id the item id
177
+ * @param int $key the meta key
178
+ * @param boolean $single single or multiple
179
+ * @return mixed item meta
180
+ */
181
+ public static function get_item_meta( $object, $item_id, $key = '', $single = false ) {
182
+ if (function_exists('wc_get_order_item_meta')) {
183
+ $item_meta = wc_get_order_item_meta( $item_id, $key, $single );
184
+ } else {
185
+ $item_meta = $object->get_item_meta( $item_id, $key, $single );
186
+ }
187
+ return $item_meta;
188
+ }
189
+
190
+ /**
191
+ * Backports WC_Order::get_status() to pre-3.0.0
192
+ *
193
+ * @since 4.6.0-dev
194
+ * @param \WC_Order $order the order object
195
+ * @return string order status
196
+ */
197
+ public static function get_status( \WC_Order $order ) {
198
+
199
+ if ( method_exists( $order, 'get_status' ) ) {
200
+ return $order->get_status();
201
+ } else {
202
+ return $order->status;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Order item CRUD compatibility method to add a coupon to an order.
208
+ *
209
+ * @since 4.6.0-dev
210
+ * @param \WC_Order $order the order object
211
+ * @param array $code the coupon code
212
+ * @param int $discount the discount amount.
213
+ * @param int $discount_tax the discount tax amount.
214
+ * @return int the order item ID
215
+ */
216
+ public static function add_coupon( \WC_Order $order, $code = array(), $discount = 0, $discount_tax = 0 ) {
217
+
218
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
219
+
220
+ $item = new \WC_Order_Item_Coupon();
221
+
222
+ $item->set_props( array(
223
+ 'code' => $code,
224
+ 'discount' => $discount,
225
+ 'discount_tax' => $discount_tax,
226
+ 'order_id' => $order->get_id(),
227
+ ) );
228
+
229
+ $item->save();
230
+
231
+ $order->add_item( $item );
232
+
233
+ return $item->get_id();
234
+
235
+ } else {
236
+
237
+ return $order->add_coupon( $code, $discount, $discount_tax );
238
+ }
239
+ }
240
+
241
+
242
+ /**
243
+ * Order item CRUD compatibility method to add a fee to an order.
244
+ *
245
+ * @since 4.6.0-dev
246
+ * @param \WC_Order $order the order object
247
+ * @param object $fee the fee to add
248
+ * @return int|\WC_Order_Item the order item ID
249
+ */
250
+ public static function add_fee( \WC_Order $order, $fee ) {
251
+
252
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
253
+
254
+ $item = new \WC_Order_Item_Fee();
255
+
256
+ $item->set_props( array(
257
+ 'name' => $fee->name,
258
+ 'tax_class' => $fee->taxable ? $fee->tax_class : 0,
259
+ 'total' => $fee->amount,
260
+ 'total_tax' => $fee->tax,
261
+ 'taxes' => array(
262
+ 'total' => $fee->tax_data,
263
+ ),
264
+ 'order_id' => $order->get_id(),
265
+ ) );
266
+
267
+ $item->save();
268
+
269
+ $order->add_item( $item );
270
+
271
+ return $item->get_id();
272
+
273
+ } else {
274
+
275
+ return $order->add_fee( $fee );
276
+ }
277
+ }
278
+
279
+
280
+ /**
281
+ * Order item CRUD compatibility method to update an order coupon.
282
+ *
283
+ * @since 4.6.0-dev
284
+ * @param \WC_Order $order the order object
285
+ * @param int|\WC_Order_Item $item the order item ID
286
+ * @param array $args {
287
+ * The coupon item args.
288
+ *
289
+ * @type string $code the coupon code
290
+ * @type float $discount the coupon discount amount
291
+ * @type float $discount_tax the coupon discount tax amount
292
+ * }
293
+ * @return int|bool the order item ID or false on failure
294
+ */
295
+ public static function update_coupon( \WC_Order $order, $item, $args ) {
296
+
297
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
298
+
299
+ if ( is_numeric( $item ) ) {
300
+ $item = $order->get_item( $item );
301
+ }
302
+
303
+ if ( ! is_object( $item ) || ! $item->is_type( 'coupon' ) ) {
304
+ return false;
305
+ }
306
+
307
+ if ( ! $order->get_id() ) {
308
+ $order->save();
309
+ }
310
+
311
+ $item->set_order_id( $order->get_id() );
312
+ $item->set_props( $args );
313
+ $item->save();
314
+
315
+ return $item->get_id();
316
+
317
+ } else {
318
+
319
+ // convert 3.0+ args for backwards compatibility
320
+ if ( isset( $args['discount'] ) ) {
321
+ $args['discount_amount'] = $args['discount'];
322
+ }
323
+ if ( isset( $args['discount_tax'] ) ) {
324
+ $args['discount_amount_tax'] = $args['discount_tax'];
325
+ }
326
+
327
+ return $order->update_coupon( $item, $args );
328
+ }
329
+ }
330
+
331
+
332
+ /**
333
+ * Order item CRUD compatibility method to update an order fee.
334
+ *
335
+ * @since 4.6.0-dev
336
+ * @param \WC_Order $order the order object
337
+ * @param int $item the order item ID
338
+ * @param array $args {
339
+ * The fee item args.
340
+ *
341
+ * @type string $name the fee name
342
+ * @type string $tax_class the fee's tax class
343
+ * @type float $line_total the fee total amount
344
+ * @type float $line_tax the fee tax amount
345
+ * }
346
+ * @return int|bool the order item ID or false on failure
347
+ */
348
+ public static function update_fee( \WC_Order $order, $item, $args ) {
349
+
350
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
351
+
352
+ if ( is_numeric( $item ) ) {
353
+ $item = $order->get_item( $item );
354
+ }
355
+
356
+ if ( ! is_object( $item ) || ! $item->is_type( 'fee' ) ) {
357
+ return false;
358
+ }
359
+
360
+ if ( ! $order->get_id() ) {
361
+ $order->save();
362
+ }
363
+
364
+ $item->set_order_id( $order->get_id() );
365
+ $item->set_props( $args );
366
+ $item->save();
367
+
368
+ return $item->get_id();
369
+
370
+ } else {
371
+
372
+ return $order->update_fee( $item, $args );
373
+ }
374
+ }
375
+
376
+
377
+ /**
378
+ * Backports wc_reduce_stock_levels() to pre-3.0.0
379
+ *
380
+ * @since 4.6.0-dev
381
+ * @param \WC_Order $order the order object
382
+ */
383
+ public static function reduce_stock_levels( \WC_Order $order ) {
384
+
385
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
386
+ wc_reduce_stock_levels( $order->get_id() );
387
+ } else {
388
+ $order->reduce_order_stock();
389
+ }
390
+ }
391
+
392
+
393
+ /**
394
+ * Backports wc_update_total_sales_counts() to pre-3.0.0
395
+ *
396
+ * @since 4.6.0-dev
397
+ * @param \WC_Order $order the order object
398
+ */
399
+ public static function update_total_sales_counts( \WC_Order $order ) {
400
+
401
+ if ( WC_Core::is_wc_version_gte_3_0() ) {
402
+ wc_update_total_sales_counts( $order->get_id() );
403
+ } else {
404
+ $order->record_product_sales();
405
+ }
406
+ }
407
+
408
+
409
+ }
410
+
411
+
412
+ endif; // Class exists check
includes/documents/abstract-wcpdf-order-document.php CHANGED
@@ -304,12 +304,18 @@ abstract class Order_Document {
304
  do_action( 'wpo_wcpdf_delete_document', $this, $order );
305
  }
306
 
307
- public function regenerate( $order = null ) {
308
  $order = empty( $order ) ? $this->order : $order;
309
  if ( empty( $order ) ) {
310
  return; //Nothing to update
311
  }
312
 
 
 
 
 
 
 
313
  //Get most current settings
314
  $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
315
  $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
304
  do_action( 'wpo_wcpdf_delete_document', $this, $order );
305
  }
306
 
307
+ public function regenerate( $order = null, $data = null ) {
308
  $order = empty( $order ) ? $this->order : $order;
309
  if ( empty( $order ) ) {
310
  return; //Nothing to update
311
  }
312
 
313
+ // pass data to setter functions
314
+ if( ! empty( $data ) ) {
315
+ $this->set_data( $data, $order );
316
+ $this->save();
317
+ }
318
+
319
  //Get most current settings
320
  $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
321
  $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
includes/documents/class-wcpdf-document-number.php CHANGED
@@ -173,8 +173,17 @@ class Document_Number {
173
  }
174
 
175
  // Padding
176
- if ( ctype_digit( (string)$this->padding ) ) {
177
- $number = sprintf('%0'.$this->padding.'d', $number);
 
 
 
 
 
 
 
 
 
178
  }
179
 
180
  // Add prefix & suffix
173
  }
174
 
175
  // Padding
176
+ $padding_string = '';
177
+ if ( function_exists('ctype_digit') ) { // requires the Ctype extension
178
+ if ( ctype_digit( (string) $this->padding ) ) {
179
+ $padding_string = (string) $this->padding;
180
+ }
181
+ } elseif ( !empty( $this->padding ) ) {
182
+ $padding_string = (string) absint($this->padding);
183
+ }
184
+
185
+ if ( !empty( $padding_string ) ) {
186
+ $number = sprintf('%0'.$padding_string.'d', $number);
187
  }
188
 
189
  // Add prefix & suffix
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: pomegranate
3
  Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
- Tested up to: 5.5
7
  Requires PHP: 5.3
8
- Stable tag: 2.7.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -102,6 +102,13 @@ There's a setting on the Status tab of the settings page that allows you to togg
102
 
103
  == Changelog ==
104
 
 
 
 
 
 
 
 
105
  = 2.7.1 =
106
  * New: Redesigned action buttons
107
  * New: Randomized temporary folder name for easier protection
3
  Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
+ Tested up to: 5.6
7
  Requires PHP: 5.3
8
+ Stable tag: 2.7.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
102
 
103
  == Changelog ==
104
 
105
+ = 2.7.2 =
106
+ * Fix: Update invoice number and date when regenerating document from edit mode
107
+ * Fix: Prevent infinite loop when temporary folder is not writable
108
+ * Fix: Prevent layout issues when custom order data exceeds column width
109
+ * Fix: Error when PHP Ctype extension is not installed
110
+ * Tested up to WooCommerce 4.8 & WP 5.6
111
+
112
  = 2.7.1 =
113
  * New: Redesigned action buttons
114
  * New: Randomized temporary folder name for easier protection
templates/Simple/style.css CHANGED
@@ -127,6 +127,16 @@ td.order-data {
127
  width: 40%;
128
  }
129
 
 
 
 
 
 
 
 
 
 
 
130
  .invoice .shipping-address {
131
  width: 30%;
132
  }
@@ -135,11 +145,6 @@ td.order-data {
135
  width: 30%;
136
  }
137
 
138
- td.order-data table th {
139
- font-weight: normal;
140
- padding-right: 2mm;
141
- }
142
-
143
  /* Order details */
144
  table.order-details {
145
  width:100%;
127
  width: 40%;
128
  }
129
 
130
+ td.order-data table {
131
+ width: 100%;
132
+ }
133
+
134
+ td.order-data table th {
135
+ font-weight: normal;
136
+ padding-right: 2mm;
137
+ width: 50%;
138
+ }
139
+
140
  .invoice .shipping-address {
141
  width: 30%;
142
  }
145
  width: 30%;
146
  }
147
 
 
 
 
 
 
148
  /* Order details */
149
  table.order-details {
150
  width:100%;
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,14 +3,14 @@
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.7.1
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
10
  * License URI: http://www.opensource.org/licenses/gpl-license.php
11
  * Text Domain: woocommerce-pdf-invoices-packing-slips
12
  * WC requires at least: 2.2.0
13
- * WC tested up to: 4.7.0
14
  */
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
@@ -21,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
21
 
22
  class WPO_WCPDF {
23
 
24
- public $version = '2.7.1';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
 
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.7.2
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
10
  * License URI: http://www.opensource.org/licenses/gpl-license.php
11
  * Text Domain: woocommerce-pdf-invoices-packing-slips
12
  * WC requires at least: 2.2.0
13
+ * WC tested up to: 4.8.0
14
  */
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.7.2';
25
  public $plugin_basename;
26
  public $legacy_mode;
27