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 | 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 +20 -1
- assets/js/order-script.js +29 -9
- includes/class-wcpdf-admin.php +138 -125
- includes/class-wcpdf-install.php +9 -5
- includes/class-wcpdf-main.php +114 -12
- includes/compatibility/class-wc-order-compatibility.php +412 -412
- includes/documents/abstract-wcpdf-order-document.php +7 -1
- includes/documents/class-wcpdf-document-number.php +11 -2
- readme.txt +9 -2
- templates/Simple/style.css +10 -5
- woocommerce-pdf-invoices-packingslips.php +3 -3
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:
|
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:
|
93 |
-
data:
|
94 |
-
action
|
95 |
-
security:
|
96 |
-
|
97 |
-
order_id:
|
|
|
98 |
},
|
99 |
-
type:
|
100 |
-
context:
|
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
|
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 |
-
<
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
<
|
391 |
-
<p>
|
392 |
-
<
|
393 |
-
|
|
|
|
|
394 |
</p>
|
395 |
-
</
|
396 |
-
</div>
|
397 |
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
|
|
403 |
</p>
|
404 |
-
</
|
405 |
-
</div>
|
406 |
-
|
407 |
-
<?php do_action( 'wpo_wcpdf_meta_box_after_document_data', $invoice, $order ); ?>
|
408 |
|
409 |
-
|
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 |
-
<
|
422 |
<?php endif; ?>
|
423 |
-
</
|
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 |
-
|
438 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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="
|
455 |
<?php else : ?>
|
456 |
-
<p><textarea name="
|
457 |
<?php endif; ?>
|
458 |
</p>
|
459 |
</div>
|
460 |
</p>
|
461 |
-
</
|
|
|
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 |
-
|
535 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
$
|
|
|
|
|
779 |
|
780 |
try {
|
781 |
-
$document = wcpdf_get_document( $
|
782 |
if ( !empty($document) && $document->exists() ) {
|
783 |
-
|
|
|
|
|
|
|
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
|
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
|
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 (
|
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 (
|
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 (
|
402 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
493 |
|
494 |
-
|
495 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
}
|
497 |
|
498 |
// create subfolders & protect
|
499 |
-
|
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) )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
7 |
Requires PHP: 5.3
|
8 |
-
Stable tag: 2.7.
|
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.
|
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.
|
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.
|
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 |
|