WooCommerce PDF Invoices & Packing Slips - Version 1.5.29

Version Description

  • Translations: Added Croation (Thanks Neven/Spine ICT!), updated French (Thanks Sabra!)
  • Tweak: filter shop address before checking if it's empty
  • Dev: added $order to wpo_wcpdf_template_file filter
Download this release

Release Info

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

Code changes from version 1.5.28 to 1.5.29

includes/class-wcpdf-export.php CHANGED
@@ -1,1188 +1,1197 @@
1
- <?php
2
- /**
3
- * PDF Export class
4
- */
5
- if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
6
-
7
- class WooCommerce_PDF_Invoices_Export {
8
-
9
- public $template_directory_name;
10
- public $template_base_path;
11
- public $template_default_base_path;
12
- public $template_default_base_uri;
13
- public $template_path;
14
-
15
- public $order;
16
- public $template_type;
17
- public $order_id;
18
- public $output_body;
19
-
20
- /**
21
- * Constructor
22
- */
23
- public function __construct() {
24
- global $woocommerce;
25
- $this->order = new WC_Order('');
26
- $this->general_settings = get_option('wpo_wcpdf_general_settings');
27
- $this->template_settings = get_option('wpo_wcpdf_template_settings');
28
- $this->debug_settings = get_option('wpo_wcpdf_debug_settings');
29
-
30
- $this->template_directory_name = 'pdf';
31
- $this->template_base_path = (defined('WC_TEMPLATE_PATH')?WC_TEMPLATE_PATH:$woocommerce->template_url) . $this->template_directory_name . '/';
32
- $this->template_default_base_path = WooCommerce_PDF_Invoices::$plugin_path . 'templates/' . $this->template_directory_name . '/';
33
- $this->template_default_base_uri = WooCommerce_PDF_Invoices::$plugin_url . 'templates/' . $this->template_directory_name . '/';
34
-
35
- $this->template_path = isset( $this->template_settings['template_path'] )?$this->template_settings['template_path']:'';
36
-
37
- // backwards compatible template path (1.4.4+ uses relative paths instead of absolute)
38
- $backslash_abspath = str_replace('/', '\\', ABSPATH);
39
- if (strpos($this->template_path, ABSPATH) === false && strpos($this->template_path, $backslash_abspath) === false) {
40
- // add site base path, double check it exists!
41
- if ( file_exists( ABSPATH . $this->template_path ) ) {
42
- $this->template_path = ABSPATH . $this->template_path;
43
- }
44
- }
45
-
46
- if ( file_exists( $this->template_path . '/template-functions.php' ) ) {
47
- require_once( $this->template_path . '/template-functions.php' );
48
- }
49
-
50
- // make page number replacements
51
- add_action( 'wpo_wcpdf_processed_template_html', array($this, 'clear_page_number_styles' ), 10, 3 );
52
- add_action( 'wpo_wcpdf_after_dompdf_render', array($this, 'page_number_replacements' ), 9, 4 );
53
-
54
- add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ));
55
- add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3);
56
- add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_numer' ), 10, 2 );
57
-
58
- // check if an invoice number filter has already been registered, if not, use settings
59
- if ( !has_filter( 'wpo_wcpdf_invoice_number' ) ) {
60
- add_filter( 'wpo_wcpdf_invoice_number', array( $this, 'format_invoice_number' ), 20, 4 );
61
- }
62
-
63
- if ( isset($this->debug_settings['enable_debug'])) {
64
- $this->enable_debug();
65
- }
66
-
67
- if ( isset($this->debug_settings['html_output'])) {
68
- add_filter( 'wpo_wcpdf_output_html', '__return_true' );
69
- add_filter( 'wpo_wcpdf_use_path', '__return_false' );
70
- }
71
-
72
- // WooCommerce Subscriptions compatibility
73
- if ( class_exists('WC_Subscriptions') ) {
74
- if ( version_compare( WC_Subscriptions::$version, '2.0', '<' ) ) {
75
- add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'woocommerce_subscriptions_renewal_order_created' ), 10, 4 );
76
- } else {
77
- add_action( 'wcs_renewal_order_created', array( $this, 'wcs_renewal_order_created' ), 10, 2 );
78
- }
79
- }
80
-
81
- // WooCommerce Product Bundles compatibility (add row classes)
82
- if ( class_exists('WC_Bundles') ) {
83
- add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
84
- }
85
-
86
- // WooCommerce Chained Products compatibility (add row classes)
87
- if ( class_exists('SA_WC_Chained_Products') ) {
88
- add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
89
- }
90
-
91
- // qTranslate-X compatibility
92
- if ( function_exists('qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
93
- $this->qtranslatex_filters();
94
- }
95
- }
96
-
97
- /**
98
- * Install/create plugin tmp folders
99
- */
100
- public function init_tmp ( $tmp_base ) {
101
- // create plugin base temp folder
102
- @mkdir( $tmp_base );
103
-
104
- // create subfolders & protect
105
- $subfolders = array( 'attachments', 'fonts', 'dompdf' );
106
- foreach ( $subfolders as $subfolder ) {
107
- $path = $tmp_base . $subfolder . '/';
108
- @mkdir( $path );
109
-
110
- // copy font files
111
- if ( $subfolder == 'fonts' ) {
112
- $this->copy_fonts( $path );
113
- }
114
-
115
- // create .htaccess file and empty index.php to protect in case an open webfolder is used!
116
- @file_put_contents( $path . '.htaccess', 'deny from all' );
117
- @touch( $path . 'index.php' );
118
- }
119
-
120
- }
121
-
122
- /**
123
- * Copy DOMPDF fonts to wordpress tmp folder
124
- */
125
- public function copy_fonts ( $path ) {
126
- $dompdf_font_dir = WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/lib/fonts/";
127
-
128
- // first try the easy way with glob!
129
- if ( function_exists('glob') ) {
130
- $files = glob($dompdf_font_dir."*.*");
131
- foreach($files as $file){
132
- if(!is_dir($file) && is_readable($file)) {
133
- $dest = $path . basename($file);
134
- copy($file, $dest);
135
- }
136
- }
137
- } else {
138
- // fallback method using font cache file (glob is disabled on some servers with disable_functions)
139
- $font_cache_file = $dompdf_font_dir . "dompdf_font_family_cache.php";
140
- $font_cache_dist_file = $dompdf_font_dir . "dompdf_font_family_cache.dist.php";
141
- $fonts = @require_once( $font_cache_file );
142
- $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm' );
143
-
144
- foreach ($fonts as $font_family => $filenames) {
145
- foreach ($filenames as $filename) {
146
- foreach ($extensions as $extension) {
147
- $file = $filename.$extension;
148
- if (file_exists($file)) {
149
- $dest = $path . basename($file);
150
- copy($file, $dest);
151
- }
152
- }
153
- }
154
- }
155
-
156
- // copy cache files separately
157
- copy($font_cache_file, $path.basename($font_cache_file));
158
- copy($font_cache_dist_file, $path.basename($font_cache_dist_file));
159
- }
160
-
161
- }
162
-
163
- /**
164
- * Return tmp path for different plugin processes
165
- */
166
- public function tmp_path ( $type = '' ) {
167
- // get temp setting
168
- $old_tmp = isset($this->debug_settings['old_tmp']);
169
-
170
- $tmp_base = $this->get_tmp_base();
171
- if (!$old_tmp) {
172
- // check if tmp folder exists => if not, initialize
173
- if ( !@is_dir( $tmp_base ) ) {
174
- $this->init_tmp( $tmp_base );
175
- }
176
- }
177
-
178
- if ( empty( $type ) ) {
179
- return $tmp_base;
180
- }
181
-
182
- switch ( $type ) {
183
- case 'DOMPDF_TEMP_DIR':
184
- // original value : sys_get_temp_dir()
185
- // 1.5+ : $tmp_base . 'dompdf'
186
- $tmp_path = $old_tmp ? sys_get_temp_dir() : $tmp_base . 'dompdf';
187
- break;
188
- case 'DOMPDF_FONT_DIR': // NEEDS TRAILING SLASH!
189
- // original value : DOMPDF_DIR."/lib/fonts/"
190
- // 1.5+ : $tmp_base . 'fonts/'
191
- $tmp_path = $old_tmp ? DOMPDF_DIR."/lib/fonts/" : $tmp_base . 'fonts/';
192
- break;
193
- case 'DOMPDF_FONT_CACHE':
194
- // original value : DOMPDF_FONT_DIR
195
- // 1.5+ : $tmp_base . 'fonts'
196
- $tmp_path = $old_tmp ? DOMPDF_FONT_DIR : $tmp_base . 'fonts';
197
- break;
198
- case 'attachments':
199
- // original value : WooCommerce_PDF_Invoices::$plugin_path . 'tmp/'
200
- // 1.5+ : $tmp_base . 'attachments/'
201
- $tmp_path = $old_tmp ? WooCommerce_PDF_Invoices::$plugin_path . 'tmp/' : $tmp_base . 'attachments/';
202
- break;
203
- default:
204
- $tmp_path = $tmp_base . $type;
205
- break;
206
- }
207
-
208
- // double check for existence, in case tmp_base was installed, but subfolder not created
209
- if ( !@is_dir( $tmp_path ) ) {
210
- @mkdir( $tmp_path );
211
- }
212
-
213
- return $tmp_path;
214
- }
215
-
216
- /**
217
- * return the base tmp folder (usually uploads)
218
- */
219
- public function get_tmp_base () {
220
- // wp_upload_dir() is used to set the base temp folder, under which a
221
- // 'wpo_wcpdf' folder and several subfolders are created
222
- //
223
- // wp_upload_dir() will:
224
- // * default to WP_CONTENT_DIR/uploads
225
- // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
226
- //
227
- // May also be overridden by the wpo_wcpdf_tmp_path filter
228
-
229
- $upload_dir = wp_upload_dir();
230
- $upload_base = trailingslashit( $upload_dir['basedir'] );
231
- $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
232
- return $tmp_base;
233
- }
234
-
235
- /**
236
- * Generate the template output
237
- */
238
- public function process_template( $template_type, $order_ids ) {
239
- $this->template_type = $template_type;
240
- $order_ids = apply_filters( 'wpo_wcpdf_process_order_ids', $order_ids, $template_type );
241
-
242
- // filter out trashed orders
243
- foreach ($order_ids as $key => $order_id) {
244
- $order_status = get_post_status( $order_id );
245
- if ( $order_status == 'trash' ) {
246
- unset( $order_ids[ $key ] );
247
- }
248
- }
249
- // sharing is caring!
250
- $this->order_ids = $order_ids;
251
-
252
- // throw error when no order ids
253
- if ( empty( $order_ids ) ) {
254
- throw new Exception('No orders to export!');
255
- }
256
-
257
- do_action( 'wpo_wcpdf_process_template', $template_type );
258
-
259
- $output_html = array();
260
- foreach ($order_ids as $order_id) {
261
- $this->order = new WC_Order( $order_id );
262
- do_action( 'wpo_wcpdf_process_template_order', $template_type, $order_id );
263
-
264
- $template = $this->template_path . '/' . $template_type . '.php';
265
- $template = apply_filters( 'wpo_wcpdf_template_file', $template, $template_type );
266
-
267
- if (!file_exists($template)) {
268
- throw new Exception('Template not found! Check if the following file exists: <pre>'.$template.'</pre><br/>');
269
- }
270
-
271
- // Set the invoice number
272
- if ( $template_type == 'invoice' ) {
273
- $this->set_invoice_number( $order_id );
274
- }
275
-
276
- $output_html[$order_id] = $this->get_template($template);
277
-
278
- // store meta to be able to check if an invoice for an order has been created already
279
- if ( $template_type == 'invoice' ) {
280
- update_post_meta( $order_id, '_wcpdf_invoice_exists', 1 );
281
- }
282
-
283
-
284
- // Wipe post from cache
285
- wp_cache_delete( $order_id, 'posts' );
286
- wp_cache_delete( $order_id, 'post_meta' );
287
- }
288
-
289
- $print_script = "<script language=javascript>window.onload = function(){ window.print(); };</script>";
290
- // <div style="page-break-before: always;"></div>
291
- $page_break = "\n<div style=\"page-break-before: always;\"></div>\n";
292
-
293
-
294
- if (apply_filters('wpo_wcpdf_output_html', false, $template_type) && apply_filters('wpo_wcpdf_print_html', false, $template_type)) {
295
- $this->output_body = $print_script . implode($page_break, $output_html);
296
- } else {
297
- $this->output_body = implode($page_break, $output_html);
298
- }
299
-
300
- // Try to clean up a bit of memory
301
- unset($output_html);
302
-
303
- $template_wrapper = $this->template_path . '/html-document-wrapper.php';
304
-
305
- if (!file_exists($template_wrapper)) {
306
- throw new Exception('Template wrapper not found! Check if the following file exists: <pre>'.$template_wrapper.'</pre><br/>');
307
- }
308
-
309
- $complete_document = $this->get_template($template_wrapper);
310
-
311
- // Try to clean up a bit of memory
312
- unset($this->output_body);
313
-
314
- // clean up special characters
315
- $complete_document = utf8_decode(mb_convert_encoding($complete_document, 'HTML-ENTITIES', 'UTF-8'));
316
-
317
-
318
- return $complete_document;
319
- }
320
-
321
- /**
322
- * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
323
- */
324
- public function clear_page_number_styles ( $html, $template_type, $order_ids ) {
325
- $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">{{PAGE_COUNT}}</span>', $html);
326
- $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
327
- return $html;
328
- }
329
-
330
- /**
331
- * Replace {{PAGE_COUNT}} placeholder with total page count
332
- */
333
- public function page_number_replacements ( $dompdf, $html, $template_type, $order_ids ) {
334
- $placeholder = '{{PAGE_COUNT}}';
335
-
336
- // check if placeholder is used
337
- if (strpos($html, $placeholder) !== false ) {
338
- foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
339
- if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false) {
340
- $object["c"] = str_replace( $placeholder , $dompdf->get_canvas()->get_page_count() , $object["c"] );
341
- }
342
- }
343
- }
344
-
345
- return $dompdf;
346
- }
347
-
348
- /**
349
- * Create & render DOMPDF object
350
- */
351
- public function generate_pdf( $template_type, $order_ids ) {
352
- $paper_size = apply_filters( 'wpo_wcpdf_paper_format', $this->template_settings['paper_size'], $template_type );
353
- $paper_orientation = apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $template_type);
354
-
355
- do_action( 'wpo_wcpdf_before_pdf', $template_type );
356
- if ( !class_exists('DOMPDF') ) {
357
- // extra check to avoid clashes with other plugins using DOMPDF
358
- // This could have unwanted side-effects when the version that's already
359
- // loaded is different, and it could also miss fonts etc, but it's better
360
- // than not checking...
361
- require_once( WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/dompdf_config.inc.php" );
362
- }
363
-
364
- $dompdf = new DOMPDF();
365
- $html = apply_filters( 'wpo_wcpdf_processed_template_html', $this->process_template( $template_type, $order_ids ), $template_type, $order_ids );
366
- $dompdf->load_html( $html );
367
- $dompdf->set_paper( $paper_size, $paper_orientation );
368
- $dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $html, $template_type, $order_ids );
369
- $dompdf->render();
370
- $dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $html, $template_type, $order_ids );
371
- do_action( 'wpo_wcpdf_after_pdf', $template_type );
372
-
373
- // Try to clean up a bit of memory
374
- unset($complete_pdf);
375
-
376
- return $dompdf;
377
- }
378
-
379
- /**
380
- * Stream PDF
381
- */
382
- public function stream_pdf( $template_type, $order_ids, $filename ) {
383
- $dompdf = $this->generate_pdf( $template_type, $order_ids );
384
- $dompdf->stream($filename);
385
- }
386
-
387
- /**
388
- * Get PDF
389
- */
390
- public function get_pdf( $template_type, $order_ids ) {
391
- try {
392
- $dompdf = $this->generate_pdf( $template_type, $order_ids );
393
- return $dompdf->output();
394
- } catch (Exception $e) {
395
- echo $e->getMessage();
396
- return false;
397
- }
398
-
399
- }
400
-
401
- /**
402
- * Load and generate the template output with ajax
403
- */
404
- public function generate_pdf_ajax() {
405
- // Check the nonce
406
- if( empty( $_GET['action'] ) || ! is_user_logged_in() || !check_admin_referer( $_GET['action'] ) ) {
407
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
408
- }
409
-
410
- // Check if all parameters are set
411
- if( empty( $_GET['template_type'] ) || empty( $_GET['order_ids'] ) ) {
412
- wp_die( __( 'Some of the export parameters are missing.', 'wpo_wcpdf' ) );
413
- }
414
-
415
- $order_ids = (array) explode('x',$_GET['order_ids']);
416
- // Process oldest first: reverse $order_ids array
417
- $order_ids = array_reverse($order_ids);
418
-
419
- // Check the user privileges
420
- if( apply_filters( 'wpo_wcpdf_check_privs', !current_user_can( 'manage_woocommerce_orders' ) && !current_user_can( 'edit_shop_orders' ) && !isset( $_GET['my-account'] ), $order_ids ) ) {
421
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
422
- }
423
-
424
- // User call from my-account page
425
- if ( isset( $_GET['my-account'] ) ) {
426
- // Only for single orders!
427
- if ( count( $order_ids ) > 1 ) {
428
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
429
- }
430
-
431
- // Get user_id of order
432
- $this->order = new WC_Order ( $order_ids[0] );
433
-
434
- // Check if current user is owner of order IMPORTANT!!!
435
- if ( $this->order->user_id != get_current_user_id() ) {
436
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
437
- }
438
-
439
- // if we got here, we're safe to go!
440
- }
441
-
442
- // Generate the output
443
- $template_type = $_GET['template_type'];
444
- // die($this->process_template( $template_type, $order_ids )); // or use the filter switch below!
445
-
446
- if (apply_filters('wpo_wcpdf_output_html', false, $template_type)) {
447
- // Output html to browser for debug
448
- // NOTE! images will be loaded with the server path by default
449
- // use the wpo_wcpdf_use_path filter (return false) to change this to http urls
450
- die($this->process_template( $template_type, $order_ids ));
451
- }
452
-
453
- if ( !($pdf = $this->get_pdf( $template_type, $order_ids )) ) {
454
- exit;
455
- }
456
-
457
- $filename = $this->build_filename( $template_type, $order_ids, 'download' );
458
-
459
- do_action( 'wpo_wcpdf_created_manually', $pdf, $filename );
460
-
461
- // Get output setting
462
- $output_mode = isset($this->general_settings['download_display'])?$this->general_settings['download_display']:'';
463
-
464
- // Switch headers according to output setting
465
- if ( $output_mode == 'display' || empty($output_mode) ) {
466
- header('Content-type: application/pdf');
467
- header('Content-Disposition: inline; filename="'.$filename.'"');
468
- } else {
469
- header('Content-Description: File Transfer');
470
- header('Content-Type: application/octet-stream');
471
- header('Content-Disposition: attachment; filename="'.$filename.'"');
472
- header('Content-Transfer-Encoding: binary');
473
- header('Connection: Keep-Alive');
474
- header('Expires: 0');
475
- header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
476
- header('Pragma: public');
477
- }
478
-
479
- // output PDF data
480
- echo($pdf);
481
-
482
- exit;
483
- }
484
-
485
- /**
486
- * Build filename
487
- */
488
- public function build_filename( $template_type, $order_ids, $context ) {
489
- $count = count($order_ids);
490
-
491
- switch ($template_type) {
492
- case 'invoice':
493
- $name = _n( 'invoice', 'invoices', $count, 'wpo_wcpdf' );
494
- $number = $this->get_display_number( $order_ids[0] );
495
- break;
496
- case 'packing-slip':
497
- $name = _n( 'packing-slip', 'packing-slips', $count, 'wpo_wcpdf' );
498
- $number = $this->order->get_order_number();
499
- break;
500
- default:
501
- $name = $template_type;
502
- $number = $this->order->get_order_number();
503
- break;
504
- }
505
-
506
- if ( $count == 1 ) {
507
- $suffix = $number;
508
- } else {
509
- $suffix = date('Y-m-d'); // 2020-11-11
510
- }
511
-
512
- $filename = $name . '-' . $suffix . '.pdf';
513
-
514
- // Filter depending on context (for legacy filter support)
515
- if ( $context == 'download' ) {
516
- $filename = apply_filters( 'wpo_wcpdf_bulk_filename', $filename, $order_ids, $name, $template_type );
517
- } elseif ( $context == 'attachment' ) {
518
- $filename = apply_filters( 'wpo_wcpdf_attachment_filename', $filename, $number, $order_ids[0] );
519
- }
520
-
521
- // Filter filename (use this filter instead of the above legacy filters!)
522
- $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $template_type, $order_ids, $context );
523
-
524
- // sanitize filename (after filters to prevent human errors)!
525
- return sanitize_file_name( $filename );
526
- }
527
-
528
- /**
529
- * Attach invoice to completed order or customer invoice email
530
- */
531
- public function attach_pdf_to_email ( $attachments, $status, $order ) {
532
- // check if all variables properly set
533
- if ( !is_object( $order ) || !isset( $status ) ) {
534
- return $attachments;
535
- }
536
-
537
- // Skip User emails
538
- if ( get_class( $order ) == 'WP_User' ) {
539
- return $attachments;
540
- }
541
-
542
- // WooCommerce Booking compatibility
543
- if ( get_post_type( $order->id ) == 'wc_booking' && isset($order->order) ) {
544
- // $order is actually a WC_Booking object!
545
- $order = $order->order;
546
- }
547
-
548
- // do not process low stock notifications, user emails etc!
549
- if ( in_array( $status, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order->id ) != 'shop_order' ) {
550
- return $attachments;
551
- }
552
-
553
- // Disable free setting check
554
- $order_total = $order->get_total();
555
- if ( $order_total == 0 && isset($this->general_settings['disable_free']) ) {
556
- return $attachments;
557
- }
558
-
559
- $this->order = $order;
560
-
561
- $tmp_path = $this->tmp_path('attachments');
562
-
563
- // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
564
- array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
565
-
566
- // set allowed statuses for invoices
567
- $invoice_allowed = isset($this->general_settings['email_pdf']) ? array_keys( $this->general_settings['email_pdf'] ) : array();
568
- $documents = array(
569
- 'invoice' => apply_filters( 'wpo_wcpdf_email_allowed_statuses', $invoice_allowed ), // Relevant (default) statuses: new_order, customer_invoice, customer_processing_order, customer_completed_order
570
- );
571
- $documents = apply_filters('wpo_wcpdf_attach_documents', $documents );
572
-
573
- foreach ($documents as $template_type => $allowed_statuses ) {
574
- // convert 'lazy' status name
575
- foreach ($allowed_statuses as $key => $order_status) {
576
- if ($order_status == 'completed' || $order_status == 'processing') {
577
- $allowed_statuses[$key] = "customer_" . $order_status . "_order";
578
- }
579
- }
580
-
581
- // legacy filter, use wpo_wcpdf_custom_attachment_condition instead!
582
- $attach_invoice = apply_filters('wpo_wcpdf_custom_email_condition', true, $order, $status );
583
- if ( $template_type == 'invoice' && !$attach_invoice ) {
584
- // don't attach invoice, continue with other documents
585
- continue;
586
- }
587
-
588
- // use this filter to add an extra condition - return false to disable the PDF attachment
589
- $attach_document = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $status, $template_type );
590
- if( in_array( $status, $allowed_statuses ) && $attach_document ) {
591
- // create pdf data
592
- $pdf_data = $this->get_pdf( $template_type, (array) $order->id );
593
-
594
- if ( !$pdf_data ) {
595
- // something went wrong, continue trying with other documents
596
- continue;
597
- }
598
-
599
- // compose filename
600
- $pdf_filename = $this->build_filename( $template_type, (array) $order->id, 'attachment' );
601
-
602
- $pdf_path = $tmp_path . $pdf_filename;
603
- file_put_contents ( $pdf_path, $pdf_data );
604
- $attachments[] = $pdf_path;
605
-
606
- do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $template_type );
607
- }
608
- }
609
-
610
- return $attachments;
611
- }
612
-
613
- public function set_invoice_number( $order_id ) {
614
- // first check: get invoice number from post meta
615
- $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true );
616
-
617
- // add invoice number if it doesn't exist
618
- if ( empty($invoice_number) || !isset($invoice_number) ) {
619
- global $wpdb;
620
- // making direct DB call to avoid caching issues
621
- $next_invoice_number = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'wpo_wcpdf_next_invoice_number' ) );
622
- $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $next_invoice_number, $order_id );
623
-
624
- if ( empty($next_invoice_number) ) {
625
- // First time! We start numbering from order_number or order_id
626
-
627
- // Check if $order_number is an integer
628
- $order_number = ltrim($this->order->get_order_number(), '#');
629
- if ( ctype_digit( (string)$order_number ) ) {
630
- // order_number == integer: use as starting point.
631
- $invoice_number = $order_number;
632
- } else {
633
- // fallback: use order_id as starting point.
634
- $invoice_number = $order_id;
635
- }
636
-
637
- } else {
638
- $invoice_number = $next_invoice_number;
639
- }
640
-
641
- // reset invoice number yearly
642
- if ( isset( $this->template_settings['yearly_reset_invoice_number'] ) ) {
643
- $current_year = date("Y");
644
- $last_invoice_year = get_option( 'wpo_wcpdf_last_invoice_year' );
645
- // check first time use
646
- if ( empty( $last_invoice_year ) ) {
647
- $last_invoice_year = $current_year;
648
- update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
649
- }
650
- // check if we need to reset
651
- if ( $current_year != $last_invoice_year ) {
652
- $invoice_number = 1;
653
- update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
654
- }
655
- }
656
- // die($invoice_number);
657
-
658
- update_post_meta($order_id, '_wcpdf_invoice_number', $invoice_number);
659
- update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
660
-
661
- // increase next_order_number
662
- $update_args = array(
663
- 'option_value' => $invoice_number + 1,
664
- 'autoload' => 'yes',
665
- );
666
- $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => 'wpo_wcpdf_next_invoice_number' ) );
667
- }
668
-
669
- // store invoice_number in class object
670
- $this->invoice_number = $invoice_number;
671
-
672
- // store invoice number in _POST superglobal to prevent the number from being cleared in a save action
673
- // (http://wordpress.org/support/topic/customer-invoice-selection-from-order-detail-page-doesnt-record-invoice-id?replies=1)
674
- $_POST['_wcpdf_invoice_number'] = $invoice_number;
675
-
676
- return $invoice_number;
677
- }
678
-
679
- public function get_invoice_number( $order_id ) {
680
- // get invoice number from post meta
681
- if ( $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true ) ) {
682
- // check if we have already loaded this order
683
- if ( $this->order->id == $order_id ) {
684
- $order_number = $this->order->get_order_number();
685
- $order_date = $this->order->order_date;
686
- } else {
687
- $order = new WC_Order( $order_id );
688
- $order_number = $order->get_order_number();
689
- $order_date = $order->order_date;
690
- }
691
-
692
- return apply_filters( 'wpo_wcpdf_invoice_number', $invoice_number, $order_number, $order_id, $order_date );
693
- } else {
694
- // no invoice number for this order
695
- return false;
696
- }
697
- }
698
-
699
- /**
700
- * Add invoice number to WC REST API
701
- */
702
- public function woocommerce_api_invoice_numer ( $data, $order ) {
703
- if ( $invoice_number = $this->get_invoice_number( $order->id ) ) {
704
- $data['wpo_wcpdf_invoice_number'] = $invoice_number;
705
- } else {
706
- $data['wpo_wcpdf_invoice_number'] = '';
707
- }
708
- return $data;
709
- }
710
-
711
- /**
712
- * Reset invoice data for WooCommerce subscription renewal orders
713
- * https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
714
- */
715
- public function woocommerce_subscriptions_renewal_order_created ( $renewal_order, $original_order, $product_id, $new_order_role ) {
716
- $this->reset_invoice_data( $renewal_order->id );
717
- return $renewal_order;
718
- }
719
-
720
- public function wcs_renewal_order_created ( $renewal_order, $subscription ) {
721
- $this->reset_invoice_data( $renewal_order->id );
722
- return $renewal_order;
723
- }
724
-
725
- public function reset_invoice_data ( $order_id ) {
726
- // delete invoice number, invoice date & invoice exists meta
727
- delete_post_meta( $order_id, '_wcpdf_invoice_number' );
728
- delete_post_meta( $order_id, '_wcpdf_formatted_invoice_number' );
729
- delete_post_meta( $order_id, '_wcpdf_invoice_date' );
730
- delete_post_meta( $order_id, '_wcpdf_invoice_exists' );
731
- }
732
-
733
- public function format_invoice_number( $invoice_number, $order_number, $order_id, $order_date ) {
734
- // get format settings
735
- $formats['prefix'] = isset($this->template_settings['invoice_number_formatting_prefix'])?$this->template_settings['invoice_number_formatting_prefix']:'';
736
- $formats['suffix'] = isset($this->template_settings['invoice_number_formatting_suffix'])?$this->template_settings['invoice_number_formatting_suffix']:'';
737
- $formats['padding'] = isset($this->template_settings['invoice_number_formatting_padding'])?$this->template_settings['invoice_number_formatting_padding']:'';
738
-
739
- // Replacements
740
- $order_year = date_i18n( 'Y', strtotime( $order_date ) );
741
- $order_month = date_i18n( 'm', strtotime( $order_date ) );
742
- $invoice_date = get_post_meta($order_id,'_wcpdf_invoice_date',true);
743
- $invoice_date = empty($invoice_date) ? current_time('mysql') : $invoice_date;
744
- $invoice_year = date_i18n( 'Y', strtotime( $invoice_date ) );
745
- $invoice_month = date_i18n( 'm', strtotime( $invoice_date ) );
746
-
747
- foreach ($formats as $key => $value) {
748
- $value = str_replace('[order_year]', $order_year, $value);
749
- $value = str_replace('[order_month]', $order_month, $value);
750
- $value = str_replace('[invoice_year]', $invoice_year, $value);
751
- $value = str_replace('[invoice_month]', $invoice_month, $value);
752
- $formats[$key] = $value;
753
- }
754
-
755
- // Padding
756
- if ( ctype_digit( (string)$formats['padding'] ) ) {
757
- $invoice_number = sprintf('%0'.$formats['padding'].'d', $invoice_number);
758
- }
759
-
760
- $formatted_invoice_number = $formats['prefix'] . $invoice_number . $formats['suffix'] ;
761
-
762
- return $formatted_invoice_number;
763
- }
764
-
765
- public function get_display_number( $order_id ) {
766
- if ( !isset($this->order->id) ) {
767
- $this->order = new WC_Order ( $order_id );
768
- }
769
-
770
- if ( isset($this->template_settings['display_number']) && $this->template_settings['display_number'] == 'invoice_number' ) {
771
- // use invoice number
772
- $display_number = $this->get_invoice_number( $order_id );
773
- // die($display_number);
774
- } else {
775
- // use order number
776
- $display_number = ltrim($this->order->get_order_number(), '#');
777
- }
778
-
779
- return $display_number;
780
- }
781
-
782
- /**
783
- * Return evaluated template contents
784
- */
785
- public function get_template( $file ) {
786
- ob_start();
787
- if (file_exists($file)) {
788
- include($file);
789
- }
790
- return ob_get_clean();
791
- }
792
-
793
- /**
794
- * Get the current order
795
- */
796
- public function get_order() {
797
- return $this->order;
798
- }
799
-
800
- /**
801
- * Get the current order items
802
- */
803
- public function get_order_items() {
804
- global $woocommerce;
805
- global $_product;
806
-
807
- $items = $this->order->get_items();
808
- $data_list = array();
809
-
810
- if( sizeof( $items ) > 0 ) {
811
- foreach ( $items as $item_id => $item ) {
812
- // Array with data for the pdf template
813
- $data = array();
814
-
815
- // Set the item_id
816
- $data['item_id'] = $item_id;
817
-
818
- // Set the id
819
- $data['product_id'] = $item['product_id'];
820
- $data['variation_id'] = $item['variation_id'];
821
-
822
- // Set item name
823
- $data['name'] = $item['name'];
824
-
825
- // Set item quantity
826
- $data['quantity'] = $item['qty'];
827
-
828
- // Set the line total (=after discount)
829
- $data['line_total'] = $this->wc_price( $item['line_total'] );
830
- $data['single_line_total'] = $this->wc_price( $item['line_total'] / max( 1, $item['qty'] ) );
831
- $data['line_tax'] = $this->wc_price( $item['line_tax'] );
832
- $data['single_line_tax'] = $this->wc_price( $item['line_tax'] / max( 1, $item['qty'] ) );
833
-
834
- $line_tax_data = maybe_unserialize( isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '' );
835
- $data['tax_rates'] = $this->get_tax_rate( $item['tax_class'], $item['line_total'], $item['line_tax'], $line_tax_data );
836
-
837
- // Set the line subtotal (=before discount)
838
- $data['line_subtotal'] = $this->wc_price( $item['line_subtotal'] );
839
- $data['line_subtotal_tax'] = $this->wc_price( $item['line_subtotal_tax'] );
840
- $data['ex_price'] = $this->get_formatted_item_price ( $item, 'total', 'excl' );
841
- $data['price'] = $this->get_formatted_item_price ( $item, 'total' );
842
- $data['order_price'] = $this->order->get_formatted_line_subtotal( $item ); // formatted according to WC settings
843
-
844
- // Calculate the single price with the same rules as the formatted line subtotal (!)
845
- // = before discount
846
- $data['ex_single_price'] = $this->get_formatted_item_price ( $item, 'single', 'excl' );
847
- $data['single_price'] = $this->get_formatted_item_price ( $item, 'single' );
848
-
849
- // Pass complete item array
850
- $data['item'] = $item;
851
-
852
- // Create the product to display more info
853
- $data['product'] = null;
854
-
855
- $product = $this->order->get_product_from_item( $item );
856
-
857
- // Checking fo existance, thanks to MDesigner0
858
- if(!empty($product)) {
859
- // Set the thumbnail id DEPRICATED (does not support thumbnail sizes), use thumbnail_path or thumbnail instead
860
- $data['thumbnail_id'] = $this->get_thumbnail_id( $product );
861
-
862
- // Thumbnail (full img tag)
863
- $data['thumbnail'] = $this->get_thumbnail ( $product );
864
-
865
- // Set the single price (turned off to use more consistent calculated price)
866
- // $data['single_price'] = woocommerce_price ( $product->get_price() );
867
-
868
- // Set item SKU
869
- $data['sku'] = $product->get_sku();
870
-
871
- // Set item weight
872
- $data['weight'] = $product->get_weight();
873
-
874
- // Set item dimensions
875
- $data['dimensions'] = $product->get_dimensions();
876
-
877
- // Pass complete product object
878
- $data['product'] = $product;
879
-
880
- }
881
-
882
- // Set item meta
883
- if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
884
- $meta = new WC_Order_Item_Meta( $item['item_meta'], $product );
885
- } else {
886
- // pass complete item for WC2.4+
887
- $meta = new WC_Order_Item_Meta( $item, $product );
888
- }
889
-
890
- $data['meta'] = $meta->display( false, true );
891
-
892
- $data_list[$item_id] = apply_filters( 'wpo_wcpdf_order_item_data', $data, $this->order );
893
- }
894
- }
895
-
896
- return apply_filters( 'wpo_wcpdf_order_items_data', $data_list, $this->order );
897
- }
898
-
899
- /**
900
- * Gets price - formatted for display.
901
- *
902
- * @access public
903
- * @param mixed $item
904
- * @return string
905
- */
906
- public function get_formatted_item_price ( $item, $type, $tax_display = '' ) {
907
- $item_price = 0;
908
- $divider = ($type == 'single' && $item['qty'] != 0 )?$item['qty']:1; //divide by 1 if $type is not 'single' (thus 'total')
909
-
910
- if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) )
911
- return;
912
-
913
- if ( $tax_display == 'excl' ) {
914
- $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item )) / $divider );
915
- } else {
916
- $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item, true )) / $divider );
917
- }
918
-
919
- return $item_price;
920
- }
921
-
922
- /**
923
- * wrapper for wc2.1 depricated price function
924
- */
925
- public function wc_price( $price, $args = array() ) {
926
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
927
- // WC 2.1 or newer is used
928
- $args['currency'] = $this->order->get_order_currency();
929
- $formatted_price = wc_price( $price, $args );
930
- } else {
931
- $formatted_price = woocommerce_price( $price );
932
- }
933
-
934
- return $formatted_price;
935
- }
936
-
937
- /**
938
- * Get the tax rates/percentages for a given tax class
939
- * @param string $tax_class tax class slug
940
- * @return string $tax_rates imploded list of tax rates
941
- */
942
- public function get_tax_rate( $tax_class, $line_total, $line_tax, $line_tax_data = '' ) {
943
- if ( $line_tax == 0 ) {
944
- return '-'; // no need to determine tax rate...
945
- }
946
-
947
- // first try the easy wc2.2 way, using line_tax_data
948
- if ( !empty( $line_tax_data ) && isset($line_tax_data['total']) ) {
949
- $tax_rates = array();
950
-
951
- $line_taxes = $line_tax_data['total'];
952
- foreach ( $line_taxes as $tax_id => $tax ) {
953
- if ( !empty($tax) && $tax != 0 ) {
954
- $tax_rates[] = $this->get_tax_rate_by_id( $tax_id ) . ' %';
955
- }
956
- }
957
-
958
- $tax_rates = implode(' ,', $tax_rates );
959
- return $tax_rates;
960
- }
961
-
962
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 && !apply_filters( 'wpo_wcpdf_calculate_tax_rate', false ) ) {
963
- // WC 2.1 or newer is used
964
-
965
- // if (empty($tax_class))
966
- // $tax_class = 'standard';// does not appear to work anymore - get_rates does accept an empty tax_class though!
967
-
968
- $tax = new WC_Tax();
969
- $taxes = $tax->get_rates( $tax_class );
970
-
971
- $tax_rates = array();
972
-
973
- foreach ($taxes as $tax) {
974
- $tax_rates[$tax['label']] = round( $tax['rate'], 2 ).' %';
975
- }
976
-
977
- if (empty($tax_rates)) {
978
- // one last try: manually calculate
979
- if ( $line_total != 0) {
980
- $tax_rates[] = round( ($line_tax / $line_total)*100, 1 ).' %';
981
- } else {
982
- $tax_rates[] = '-';
983
- }
984
- }
985
-
986
- $tax_rates = implode(' ,', $tax_rates );
987
- } else {
988
- // Backwards compatibility/fallback: calculate tax from line items
989
- if ( $line_total != 0) {
990
- $tax_rates = round( ($line_tax / $line_total)*100, 1 ).' %';
991
- } else {
992
- $tax_rates = '-';
993
- }
994
- }
995
-
996
- return $tax_rates;
997
- }
998
-
999
- /**
1000
- * Returns the percentage rate (float) for a given tax rate ID.
1001
- * @param int $rate_id woocommerce tax rate id
1002
- * @return float $rate percentage rate
1003
- */
1004
- public function get_tax_rate_by_id( $rate_id ) {
1005
- global $wpdb;
1006
- $rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) );
1007
- return (float) $rate;
1008
- }
1009
-
1010
- /**
1011
- * Returns a an array with rate_id => tax rate data (array) of all tax rates in woocommerce
1012
- * @return array $tax_rate_ids keyed by id
1013
- */
1014
- public function get_tax_rate_ids() {
1015
- global $wpdb;
1016
- $rates = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates" );
1017
-
1018
- $tax_rate_ids = array();
1019
- foreach ($rates as $rate) {
1020
- // var_dump($rate->tax_rate_id);
1021
- // die($rate);
1022
- $rate_id = $rate->tax_rate_id;
1023
- unset($rate->tax_rate_id);
1024
- $tax_rate_ids[$rate_id] = (array) $rate;
1025
- }
1026
-
1027
- return $tax_rate_ids;
1028
- }
1029
-
1030
- /**
1031
- * Get order custom field
1032
- */
1033
- public function get_order_field( $field ) {
1034
- if( isset( $this->get_order()->order_custom_fields[$field] ) ) {
1035
- return $this->get_order()->order_custom_fields[$field][0];
1036
- }
1037
- return;
1038
- }
1039
-
1040
- /**
1041
- * Returns the main product image ID
1042
- * Adapted from the WC_Product class
1043
- *
1044
- * @access public
1045
- * @return string
1046
- */
1047
- public function get_thumbnail_id ( $product ) {
1048
- // DEPRICATED (does not support thumbnail sizes)
1049
- global $woocommerce;
1050
-
1051
- if ( $product->variation_id && has_post_thumbnail( $product->variation_id ) ) {
1052
- $thumbnail_id = get_post_thumbnail_id ( $product->variation_id );
1053
- } elseif ( has_post_thumbnail( $product->id ) ) {
1054
- $thumbnail_id = get_post_thumbnail_id ( $product->id );
1055
- } elseif ( ( $parent_id = wp_get_post_parent_id( $product->id ) ) && has_post_thumbnail( $parent_id ) ) {
1056
- $thumbnail_id = get_post_thumbnail_id ( $parent_id );
1057
- } else {
1058
- $thumbnail_id = $woocommerce->plugin_url() . '/assets/images/placeholder.png';
1059
- }
1060
-
1061
- return $thumbnail_id;
1062
- }
1063
-
1064
- public function get_thumbnail ( $product ) {
1065
- // Get default WooCommerce img tag (url/http)
1066
- $size = apply_filters( 'wpo_wcpdf_thumbnail_size', 'shop_thumbnail' );
1067
- $thumbnail_img_tag_url = $product->get_image( $size, array( 'title' => '' ) );
1068
-
1069
- // Extract the url from img
1070
- preg_match('/<img(.*)src(.*)=(.*)"(.*)"/U', $thumbnail_img_tag_url, $thumbnail_url );
1071
- // convert url to path
1072
- $thumbnail_path = str_replace( get_site_url() . '/', ABSPATH, array_pop($thumbnail_url));
1073
-
1074
- // Thumbnail (full img tag)
1075
- if (apply_filters('wpo_wcpdf_use_path', true) && file_exists($thumbnail_path)) {
1076
- // load img with server path by default
1077
- $thumbnail = sprintf('<img width="90" height="90" src="%s" class="attachment-shop_thumbnail wp-post-image">', $thumbnail_path );
1078
- } else {
1079
- // load img with http url when filtered
1080
- $thumbnail = $thumbnail_img_tag_url;
1081
- }
1082
-
1083
- // die($thumbnail);
1084
-
1085
- return $thumbnail;
1086
- }
1087
-
1088
- public function add_product_bundles_classes ( $classes, $template_type, $order, $item_id = '' ) {
1089
- if ( empty($item_id) ) {
1090
- // get item id from classes (backwards compatibility fix)
1091
- $class_array = explode(' ', $classes);
1092
- foreach ($class_array as $class) {
1093
- if (is_numeric($class)) {
1094
- $item_id = $class;
1095
- break;
1096
- }
1097
- }
1098
-
1099
- // if still empty, we lost the item id somewhere :(
1100
- if (empty($item_id)) {
1101
- return $classes;
1102
- }
1103
- }
1104
-
1105
- $item_meta = $order->get_item_meta( $item_id );
1106
-
1107
- if (isset($item_meta['_bundled_by'])) {
1108
- $classes = $classes . ' bundled-item';
1109
-
1110
- // check bundled item visibility
1111
- if ( ! empty( $item_meta[ '_bundled_item_hidden' ] ) ) {
1112
- $classes = $classes . ' hidden';
1113
- }
1114
-
1115
- return $classes;
1116
- } elseif (isset($item_meta['_bundled_items'])) {
1117
- return $classes . ' product-bundle';
1118
- }
1119
-
1120
- return $classes;
1121
- }
1122
-
1123
- public function add_chained_product_class ( $classes, $template_type, $order, $item_id = '' ) {
1124
- if ( empty($item_id) ) {
1125
- // get item id from classes (backwards compatibility fix)
1126
- $class_array = explode(' ', $classes);
1127
- foreach ($class_array as $class) {
1128
- if (is_numeric($class)) {
1129
- $item_id = $class;
1130
- break;
1131
- }
1132
- }
1133
-
1134
- // if still empty, we lost the item id somewhere :(
1135
- if (empty($item_id)) {
1136
- return $classes;
1137
- }
1138
- }
1139
-
1140
- $item_meta = $order->get_item_meta( $item_id );
1141
-
1142
- if (isset($item_meta['_chained_product_of'])) {
1143
- return $classes . ' chained-product';
1144
- }
1145
-
1146
- return $classes;
1147
- }
1148
-
1149
- /**
1150
- * Filter plugin strings with qTranslate-X
1151
- */
1152
- public function qtranslatex_filters() {
1153
- $use_filters = array(
1154
- 'wpo_wcpdf_shop_name' => 20,
1155
- 'wpo_wcpdf_shop_address' => 20,
1156
- 'wpo_wcpdf_footer' => 20,
1157
- 'wpo_wcpdf_order_items' => 20,
1158
- 'wpo_wcpdf_payment_method' => 20,
1159
- 'wpo_wcpdf_shipping_method' => 20,
1160
- 'wpo_wcpdf_extra_1' => 20,
1161
- 'wpo_wcpdf_extra_2' => 20,
1162
- 'wpo_wcpdf_extra_3' => 20,
1163
- );
1164
-
1165
- foreach ( $use_filters as $name => $priority ) {
1166
- add_filter( $name, 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage', $priority );
1167
- }
1168
- }
1169
-
1170
- public function enable_debug () {
1171
- error_reporting( E_ALL );
1172
- ini_set( 'display_errors', 1 );
1173
- }
1174
-
1175
- /**
1176
- * Log messages
1177
- */
1178
-
1179
- public function log( $order_id, $message ) {
1180
- $current_date_time = date("Y-m-d H:i:s");
1181
- $message = $order_id . ' ' . $current_date_time .' ' .$message ."\n";
1182
- $file = $this->tmp_path() . 'log.txt';
1183
-
1184
- file_put_contents($file, $message, FILE_APPEND);
1185
- }
1186
- }
1187
-
1188
- }
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PDF Export class
4
+ */
5
+ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Export' ) ) {
6
+
7
+ class WooCommerce_PDF_Invoices_Export {
8
+
9
+ public $template_directory_name;
10
+ public $template_base_path;
11
+ public $template_default_base_path;
12
+ public $template_default_base_uri;
13
+ public $template_path;
14
+
15
+ public $order;
16
+ public $template_type;
17
+ public $order_id;
18
+ public $output_body;
19
+
20
+ /**
21
+ * Constructor
22
+ */
23
+ public function __construct() {
24
+ global $woocommerce;
25
+ $this->order = new WC_Order('');
26
+ $this->general_settings = get_option('wpo_wcpdf_general_settings');
27
+ $this->template_settings = get_option('wpo_wcpdf_template_settings');
28
+ $this->debug_settings = get_option('wpo_wcpdf_debug_settings');
29
+
30
+ $this->template_directory_name = 'pdf';
31
+ $this->template_base_path = (defined('WC_TEMPLATE_PATH')?WC_TEMPLATE_PATH:$woocommerce->template_url) . $this->template_directory_name . '/';
32
+ $this->template_default_base_path = WooCommerce_PDF_Invoices::$plugin_path . 'templates/' . $this->template_directory_name . '/';
33
+ $this->template_default_base_uri = WooCommerce_PDF_Invoices::$plugin_url . 'templates/' . $this->template_directory_name . '/';
34
+
35
+ $this->template_path = isset( $this->template_settings['template_path'] )?$this->template_settings['template_path']:'';
36
+
37
+ // backwards compatible template path (1.4.4+ uses relative paths instead of absolute)
38
+ $backslash_abspath = str_replace('/', '\\', ABSPATH);
39
+ if (strpos($this->template_path, ABSPATH) === false && strpos($this->template_path, $backslash_abspath) === false) {
40
+ // add site base path, double check it exists!
41
+ if ( file_exists( ABSPATH . $this->template_path ) ) {
42
+ $this->template_path = ABSPATH . $this->template_path;
43
+ }
44
+ }
45
+
46
+ if ( file_exists( $this->template_path . '/template-functions.php' ) ) {
47
+ require_once( $this->template_path . '/template-functions.php' );
48
+ }
49
+
50
+ // make page number replacements
51
+ add_action( 'wpo_wcpdf_processed_template_html', array($this, 'clear_page_number_styles' ), 10, 3 );
52
+ add_action( 'wpo_wcpdf_after_dompdf_render', array($this, 'page_number_replacements' ), 9, 4 );
53
+
54
+ add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ));
55
+ add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3);
56
+ add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_numer' ), 10, 2 );
57
+
58
+ // check if an invoice number filter has already been registered, if not, use settings
59
+ if ( !has_filter( 'wpo_wcpdf_invoice_number' ) ) {
60
+ add_filter( 'wpo_wcpdf_invoice_number', array( $this, 'format_invoice_number' ), 20, 4 );
61
+ }
62
+
63
+ if ( isset($this->debug_settings['enable_debug'])) {
64
+ $this->enable_debug();
65
+ }
66
+
67
+ if ( isset($this->debug_settings['html_output'])) {
68
+ add_filter( 'wpo_wcpdf_output_html', '__return_true' );
69
+ add_filter( 'wpo_wcpdf_use_path', '__return_false' );
70
+ }
71
+
72
+ // WooCommerce Subscriptions compatibility
73
+ if ( class_exists('WC_Subscriptions') ) {
74
+ if ( version_compare( WC_Subscriptions::$version, '2.0', '<' ) ) {
75
+ add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'woocommerce_subscriptions_renewal_order_created' ), 10, 4 );
76
+ } else {
77
+ add_action( 'wcs_renewal_order_created', array( $this, 'wcs_renewal_order_created' ), 10, 2 );
78
+ }
79
+ }
80
+
81
+ // WooCommerce Product Bundles compatibility (add row classes)
82
+ if ( class_exists('WC_Bundles') ) {
83
+ add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
84
+ }
85
+
86
+ // WooCommerce Chained Products compatibility (add row classes)
87
+ if ( class_exists('SA_WC_Chained_Products') ) {
88
+ add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
89
+ }
90
+
91
+ // qTranslate-X compatibility
92
+ if ( function_exists('qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
93
+ $this->qtranslatex_filters();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Install/create plugin tmp folders
99
+ */
100
+ public function init_tmp ( $tmp_base ) {
101
+ // create plugin base temp folder
102
+ @mkdir( $tmp_base );
103
+
104
+ // create subfolders & protect
105
+ $subfolders = array( 'attachments', 'fonts', 'dompdf' );
106
+ foreach ( $subfolders as $subfolder ) {
107
+ $path = $tmp_base . $subfolder . '/';
108
+ @mkdir( $path );
109
+
110
+ // copy font files
111
+ if ( $subfolder == 'fonts' ) {
112
+ $this->copy_fonts( $path );
113
+ }
114
+
115
+ // create .htaccess file and empty index.php to protect in case an open webfolder is used!
116
+ @file_put_contents( $path . '.htaccess', 'deny from all' );
117
+ @touch( $path . 'index.php' );
118
+ }
119
+
120
+ }
121
+
122
+ /**
123
+ * Copy DOMPDF fonts to wordpress tmp folder
124
+ */
125
+ public function copy_fonts ( $path ) {
126
+ $dompdf_font_dir = WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/lib/fonts/";
127
+
128
+ // first try the easy way with glob!
129
+ if ( function_exists('glob') ) {
130
+ $files = glob($dompdf_font_dir."*.*");
131
+ foreach($files as $file){
132
+ if(!is_dir($file) && is_readable($file)) {
133
+ $dest = $path . basename($file);
134
+ copy($file, $dest);
135
+ }
136
+ }
137
+ } else {
138
+ // fallback method using font cache file (glob is disabled on some servers with disable_functions)
139
+ $font_cache_file = $dompdf_font_dir . "dompdf_font_family_cache.php";
140
+ $font_cache_dist_file = $dompdf_font_dir . "dompdf_font_family_cache.dist.php";
141
+ $fonts = @require_once( $font_cache_file );
142
+ $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm' );
143
+
144
+ foreach ($fonts as $font_family => $filenames) {
145
+ foreach ($filenames as $filename) {
146
+ foreach ($extensions as $extension) {
147
+ $file = $filename.$extension;
148
+ if (file_exists($file)) {
149
+ $dest = $path . basename($file);
150
+ copy($file, $dest);
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ // copy cache files separately
157
+ copy($font_cache_file, $path.basename($font_cache_file));
158
+ copy($font_cache_dist_file, $path.basename($font_cache_dist_file));
159
+ }
160
+
161
+ }
162
+
163
+ /**
164
+ * Return tmp path for different plugin processes
165
+ */
166
+ public function tmp_path ( $type = '' ) {
167
+ // get temp setting
168
+ $old_tmp = isset($this->debug_settings['old_tmp']);
169
+
170
+ $tmp_base = $this->get_tmp_base();
171
+ if (!$old_tmp) {
172
+ // check if tmp folder exists => if not, initialize
173
+ if ( !@is_dir( $tmp_base ) ) {
174
+ $this->init_tmp( $tmp_base );
175
+ }
176
+ }
177
+
178
+ if ( empty( $type ) ) {
179
+ return $tmp_base;
180
+ }
181
+
182
+ switch ( $type ) {
183
+ case 'DOMPDF_TEMP_DIR':
184
+ // original value : sys_get_temp_dir()
185
+ // 1.5+ : $tmp_base . 'dompdf'
186
+ $tmp_path = $old_tmp ? sys_get_temp_dir() : $tmp_base . 'dompdf';
187
+ break;
188
+ case 'DOMPDF_FONT_DIR': // NEEDS TRAILING SLASH!
189
+ // original value : DOMPDF_DIR."/lib/fonts/"
190
+ // 1.5+ : $tmp_base . 'fonts/'
191
+ $tmp_path = $old_tmp ? DOMPDF_DIR."/lib/fonts/" : $tmp_base . 'fonts/';
192
+ break;
193
+ case 'DOMPDF_FONT_CACHE':
194
+ // original value : DOMPDF_FONT_DIR
195
+ // 1.5+ : $tmp_base . 'fonts'
196
+ $tmp_path = $old_tmp ? DOMPDF_FONT_DIR : $tmp_base . 'fonts';
197
+ break;
198
+ case 'attachments':
199
+ // original value : WooCommerce_PDF_Invoices::$plugin_path . 'tmp/'
200
+ // 1.5+ : $tmp_base . 'attachments/'
201
+ $tmp_path = $old_tmp ? WooCommerce_PDF_Invoices::$plugin_path . 'tmp/' : $tmp_base . 'attachments/';
202
+ break;
203
+ default:
204
+ $tmp_path = $tmp_base . $type;
205
+ break;
206
+ }
207
+
208
+ // double check for existence, in case tmp_base was installed, but subfolder not created
209
+ if ( !@is_dir( $tmp_path ) ) {
210
+ @mkdir( $tmp_path );
211
+ }
212
+
213
+ return $tmp_path;
214
+ }
215
+
216
+ /**
217
+ * return the base tmp folder (usually uploads)
218
+ */
219
+ public function get_tmp_base () {
220
+ // wp_upload_dir() is used to set the base temp folder, under which a
221
+ // 'wpo_wcpdf' folder and several subfolders are created
222
+ //
223
+ // wp_upload_dir() will:
224
+ // * default to WP_CONTENT_DIR/uploads
225
+ // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
226
+ //
227
+ // May also be overridden by the wpo_wcpdf_tmp_path filter
228
+
229
+ $upload_dir = wp_upload_dir();
230
+ $upload_base = trailingslashit( $upload_dir['basedir'] );
231
+ $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
232
+ return $tmp_base;
233
+ }
234
+
235
+ /**
236
+ * Generate the template output
237
+ */
238
+ public function process_template( $template_type, $order_ids ) {
239
+ $this->template_type = $template_type;
240
+ $order_ids = apply_filters( 'wpo_wcpdf_process_order_ids', $order_ids, $template_type );
241
+
242
+ // custom function fix
243
+ if (function_exists('wpo_wcpdf_payment_form')) {
244
+ return false;
245
+ }
246
+
247
+ // filter out trashed orders
248
+ foreach ($order_ids as $key => $order_id) {
249
+ $order_status = get_post_status( $order_id );
250
+ if ( $order_status == 'trash' ) {
251
+ unset( $order_ids[ $key ] );
252
+ }
253
+ }
254
+ // sharing is caring!
255
+ $this->order_ids = $order_ids;
256
+
257
+ // throw error when no order ids
258
+ if ( empty( $order_ids ) ) {
259
+ throw new Exception('No orders to export!');
260
+ }
261
+
262
+ do_action( 'wpo_wcpdf_process_template', $template_type );
263
+
264
+ $output_html = array();
265
+ foreach ($order_ids as $order_id) {
266
+ $this->order = new WC_Order( $order_id );
267
+ do_action( 'wpo_wcpdf_process_template_order', $template_type, $order_id );
268
+
269
+ $template = $this->template_path . '/' . $template_type . '.php';
270
+ $template = apply_filters( 'wpo_wcpdf_template_file', $template, $template_type, $this->order );
271
+
272
+ if (!file_exists($template)) {
273
+ throw new Exception('Template not found! Check if the following file exists: <pre>'.$template.'</pre><br/>');
274
+ }
275
+
276
+ // Set the invoice number
277
+ if ( $template_type == 'invoice' ) {
278
+ $this->set_invoice_number( $order_id );
279
+ }
280
+
281
+ $output_html[$order_id] = $this->get_template($template);
282
+
283
+ // store meta to be able to check if an invoice for an order has been created already
284
+ if ( $template_type == 'invoice' ) {
285
+ update_post_meta( $order_id, '_wcpdf_invoice_exists', 1 );
286
+ }
287
+
288
+
289
+ // Wipe post from cache
290
+ wp_cache_delete( $order_id, 'posts' );
291
+ wp_cache_delete( $order_id, 'post_meta' );
292
+ }
293
+
294
+ $print_script = "<script language=javascript>window.onload = function(){ window.print(); };</script>";
295
+ // <div style="page-break-before: always;"></div>
296
+ $page_break = "\n<div style=\"page-break-before: always;\"></div>\n";
297
+
298
+
299
+ if (apply_filters('wpo_wcpdf_output_html', false, $template_type) && apply_filters('wpo_wcpdf_print_html', false, $template_type)) {
300
+ $this->output_body = $print_script . implode($page_break, $output_html);
301
+ } else {
302
+ $this->output_body = implode($page_break, $output_html);
303
+ }
304
+
305
+ // Try to clean up a bit of memory
306
+ unset($output_html);
307
+
308
+ $template_wrapper = $this->template_path . '/html-document-wrapper.php';
309
+
310
+ if (!file_exists($template_wrapper)) {
311
+ throw new Exception('Template wrapper not found! Check if the following file exists: <pre>'.$template_wrapper.'</pre><br/>');
312
+ }
313
+
314
+ $complete_document = $this->get_template($template_wrapper);
315
+
316
+ // Try to clean up a bit of memory
317
+ unset($this->output_body);
318
+
319
+ // clean up special characters
320
+ $complete_document = utf8_decode(mb_convert_encoding($complete_document, 'HTML-ENTITIES', 'UTF-8'));
321
+
322
+
323
+ return $complete_document;
324
+ }
325
+
326
+ /**
327
+ * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
328
+ */
329
+ public function clear_page_number_styles ( $html, $template_type, $order_ids ) {
330
+ $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">{{PAGE_COUNT}}</span>', $html);
331
+ $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
332
+ return $html;
333
+ }
334
+
335
+ /**
336
+ * Replace {{PAGE_COUNT}} placeholder with total page count
337
+ */
338
+ public function page_number_replacements ( $dompdf, $html, $template_type, $order_ids ) {
339
+ $placeholder = '{{PAGE_COUNT}}';
340
+
341
+ // check if placeholder is used
342
+ if (strpos($html, $placeholder) !== false ) {
343
+ foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
344
+ if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false) {
345
+ $object["c"] = str_replace( $placeholder , $dompdf->get_canvas()->get_page_count() , $object["c"] );
346
+ }
347
+ }
348
+ }
349
+
350
+ return $dompdf;
351
+ }
352
+
353
+ /**
354
+ * Create & render DOMPDF object
355
+ */
356
+ public function generate_pdf( $template_type, $order_ids ) {
357
+ $paper_size = apply_filters( 'wpo_wcpdf_paper_format', $this->template_settings['paper_size'], $template_type );
358
+ $paper_orientation = apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $template_type);
359
+
360
+ do_action( 'wpo_wcpdf_before_pdf', $template_type );
361
+ if ( !class_exists('DOMPDF') ) {
362
+ // extra check to avoid clashes with other plugins using DOMPDF
363
+ // This could have unwanted side-effects when the version that's already
364
+ // loaded is different, and it could also miss fonts etc, but it's better
365
+ // than not checking...
366
+ require_once( WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/dompdf_config.inc.php" );
367
+ }
368
+
369
+ $dompdf = new DOMPDF();
370
+ $html = apply_filters( 'wpo_wcpdf_processed_template_html', $this->process_template( $template_type, $order_ids ), $template_type, $order_ids );
371
+ $dompdf->load_html( $html );
372
+ $dompdf->set_paper( $paper_size, $paper_orientation );
373
+ $dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $html, $template_type, $order_ids );
374
+ $dompdf->render();
375
+ $dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $html, $template_type, $order_ids );
376
+ do_action( 'wpo_wcpdf_after_pdf', $template_type );
377
+
378
+ // Try to clean up a bit of memory
379
+ unset($complete_pdf);
380
+
381
+ return $dompdf;
382
+ }
383
+
384
+ /**
385
+ * Stream PDF
386
+ */
387
+ public function stream_pdf( $template_type, $order_ids, $filename ) {
388
+ $dompdf = $this->generate_pdf( $template_type, $order_ids );
389
+ $dompdf->stream($filename);
390
+ }
391
+
392
+ /**
393
+ * Get PDF
394
+ */
395
+ public function get_pdf( $template_type, $order_ids ) {
396
+ try {
397
+ $dompdf = $this->generate_pdf( $template_type, $order_ids );
398
+ return $dompdf->output();
399
+ } catch (Exception $e) {
400
+ echo $e->getMessage();
401
+ return false;
402
+ }
403
+
404
+ }
405
+
406
+ /**
407
+ * Load and generate the template output with ajax
408
+ */
409
+ public function generate_pdf_ajax() {
410
+ // Check the nonce
411
+ if( empty( $_GET['action'] ) || ! is_user_logged_in() || !check_admin_referer( $_GET['action'] ) ) {
412
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
413
+ }
414
+
415
+ // Check if all parameters are set
416
+ if( empty( $_GET['template_type'] ) || empty( $_GET['order_ids'] ) ) {
417
+ wp_die( __( 'Some of the export parameters are missing.', 'wpo_wcpdf' ) );
418
+ }
419
+
420
+ $order_ids = (array) explode('x',$_GET['order_ids']);
421
+ // Process oldest first: reverse $order_ids array
422
+ $order_ids = array_reverse($order_ids);
423
+
424
+ // Check the user privileges
425
+ if( apply_filters( 'wpo_wcpdf_check_privs', !current_user_can( 'manage_woocommerce_orders' ) && !current_user_can( 'edit_shop_orders' ) && !isset( $_GET['my-account'] ), $order_ids ) ) {
426
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
427
+ }
428
+
429
+ // User call from my-account page
430
+ if ( isset( $_GET['my-account'] ) ) {
431
+ // Only for single orders!
432
+ if ( count( $order_ids ) > 1 ) {
433
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
434
+ }
435
+
436
+ // Get user_id of order
437
+ $this->order = new WC_Order ( $order_ids[0] );
438
+
439
+ // Check if current user is owner of order IMPORTANT!!!
440
+ if ( $this->order->user_id != get_current_user_id() ) {
441
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
442
+ }
443
+
444
+ // if we got here, we're safe to go!
445
+ }
446
+
447
+ // Generate the output
448
+ $template_type = $_GET['template_type'];
449
+ // die($this->process_template( $template_type, $order_ids )); // or use the filter switch below!
450
+
451
+ if (apply_filters('wpo_wcpdf_output_html', false, $template_type)) {
452
+ // Output html to browser for debug
453
+ // NOTE! images will be loaded with the server path by default
454
+ // use the wpo_wcpdf_use_path filter (return false) to change this to http urls
455
+ die($this->process_template( $template_type, $order_ids ));
456
+ }
457
+
458
+ if ( !($pdf = $this->get_pdf( $template_type, $order_ids )) ) {
459
+ exit;
460
+ }
461
+
462
+ $filename = $this->build_filename( $template_type, $order_ids, 'download' );
463
+
464
+ do_action( 'wpo_wcpdf_created_manually', $pdf, $filename );
465
+
466
+ // Get output setting
467
+ $output_mode = isset($this->general_settings['download_display'])?$this->general_settings['download_display']:'';
468
+
469
+ // Switch headers according to output setting
470
+ if ( $output_mode == 'display' || empty($output_mode) ) {
471
+ header('Content-type: application/pdf');
472
+ header('Content-Disposition: inline; filename="'.$filename.'"');
473
+ } else {
474
+ header('Content-Description: File Transfer');
475
+ header('Content-Type: application/octet-stream');
476
+ header('Content-Disposition: attachment; filename="'.$filename.'"');
477
+ header('Content-Transfer-Encoding: binary');
478
+ header('Connection: Keep-Alive');
479
+ header('Expires: 0');
480
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
481
+ header('Pragma: public');
482
+ }
483
+
484
+ // output PDF data
485
+ echo($pdf);
486
+
487
+ exit;
488
+ }
489
+
490
+ /**
491
+ * Build filename
492
+ */
493
+ public function build_filename( $template_type, $order_ids, $context ) {
494
+ $count = count($order_ids);
495
+
496
+ switch ($template_type) {
497
+ case 'invoice':
498
+ $name = _n( 'invoice', 'invoices', $count, 'wpo_wcpdf' );
499
+ $number = $this->get_display_number( $order_ids[0] );
500
+ break;
501
+ case 'packing-slip':
502
+ $name = _n( 'packing-slip', 'packing-slips', $count, 'wpo_wcpdf' );
503
+ $number = $this->order->get_order_number();
504
+ break;
505
+ default:
506
+ $name = $template_type;
507
+ $number = $this->order->get_order_number();
508
+ break;
509
+ }
510
+
511
+ if ( $count == 1 ) {
512
+ $suffix = $number;
513
+ } else {
514
+ $suffix = date('Y-m-d'); // 2020-11-11
515
+ }
516
+
517
+ $filename = $name . '-' . $suffix . '.pdf';
518
+
519
+ // Filter depending on context (for legacy filter support)
520
+ if ( $context == 'download' ) {
521
+ $filename = apply_filters( 'wpo_wcpdf_bulk_filename', $filename, $order_ids, $name, $template_type );
522
+ } elseif ( $context == 'attachment' ) {
523
+ $filename = apply_filters( 'wpo_wcpdf_attachment_filename', $filename, $number, $order_ids[0] );
524
+ }
525
+
526
+ // Filter filename (use this filter instead of the above legacy filters!)
527
+ $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $template_type, $order_ids, $context );
528
+
529
+ // sanitize filename (after filters to prevent human errors)!
530
+ return sanitize_file_name( $filename );
531
+ }
532
+
533
+ /**
534
+ * Attach invoice to completed order or customer invoice email
535
+ */
536
+ public function attach_pdf_to_email ( $attachments, $status, $order ) {
537
+ // check if all variables properly set
538
+ if ( !is_object( $order ) || !isset( $status ) ) {
539
+ return $attachments;
540
+ }
541
+
542
+ // Skip User emails
543
+ if ( get_class( $order ) == 'WP_User' ) {
544
+ return $attachments;
545
+ }
546
+
547
+ // WooCommerce Booking compatibility
548
+ if ( get_post_type( $order->id ) == 'wc_booking' && isset($order->order) ) {
549
+ // $order is actually a WC_Booking object!
550
+ $order = $order->order;
551
+ }
552
+
553
+ // do not process low stock notifications, user emails etc!
554
+ if ( in_array( $status, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order->id ) != 'shop_order' ) {
555
+ return $attachments;
556
+ }
557
+
558
+ // Disable free setting check
559
+ $order_total = $order->get_total();
560
+ if ( $order_total == 0 && isset($this->general_settings['disable_free']) ) {
561
+ return $attachments;
562
+ }
563
+
564
+ $this->order = $order;
565
+
566
+ $tmp_path = $this->tmp_path('attachments');
567
+
568
+ // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
569
+ array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
570
+
571
+ // set allowed statuses for invoices
572
+ $invoice_allowed = isset($this->general_settings['email_pdf']) ? array_keys( $this->general_settings['email_pdf'] ) : array();
573
+ $documents = array(
574
+ 'invoice' => apply_filters( 'wpo_wcpdf_email_allowed_statuses', $invoice_allowed ), // Relevant (default) statuses: new_order, customer_invoice, customer_processing_order, customer_completed_order
575
+ );
576
+ $documents = apply_filters('wpo_wcpdf_attach_documents', $documents );
577
+
578
+ foreach ($documents as $template_type => $allowed_statuses ) {
579
+ // convert 'lazy' status name
580
+ foreach ($allowed_statuses as $key => $order_status) {
581
+ if ($order_status == 'completed' || $order_status == 'processing') {
582
+ $allowed_statuses[$key] = "customer_" . $order_status . "_order";
583
+ }
584
+ }
585
+
586
+ // legacy filter, use wpo_wcpdf_custom_attachment_condition instead!
587
+ $attach_invoice = apply_filters('wpo_wcpdf_custom_email_condition', true, $order, $status );
588
+ if ( $template_type == 'invoice' && !$attach_invoice ) {
589
+ // don't attach invoice, continue with other documents
590
+ continue;
591
+ }
592
+
593
+ // use this filter to add an extra condition - return false to disable the PDF attachment
594
+ $attach_document = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $status, $template_type );
595
+ if( in_array( $status, $allowed_statuses ) && $attach_document ) {
596
+ // create pdf data
597
+ $pdf_data = $this->get_pdf( $template_type, (array) $order->id );
598
+
599
+ if ( !$pdf_data ) {
600
+ // something went wrong, continue trying with other documents
601
+ continue;
602
+ }
603
+
604
+ // compose filename
605
+ $pdf_filename = $this->build_filename( $template_type, (array) $order->id, 'attachment' );
606
+
607
+ $pdf_path = $tmp_path . $pdf_filename;
608
+ file_put_contents ( $pdf_path, $pdf_data );
609
+ $attachments[] = $pdf_path;
610
+
611
+ do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $template_type );
612
+ }
613
+ }
614
+
615
+ return $attachments;
616
+ }
617
+
618
+ public function set_invoice_number( $order_id ) {
619
+ // first check: get invoice number from post meta
620
+ $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true );
621
+
622
+ // add invoice number if it doesn't exist
623
+ if ( empty($invoice_number) || !isset($invoice_number) ) {
624
+ global $wpdb;
625
+ // making direct DB call to avoid caching issues
626
+ $next_invoice_number = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'wpo_wcpdf_next_invoice_number' ) );
627
+ $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $next_invoice_number, $order_id );
628
+
629
+ if ( empty($next_invoice_number) ) {
630
+ // First time! We start numbering from order_number or order_id
631
+
632
+ // Check if $order_number is an integer
633
+ $order_number = ltrim($this->order->get_order_number(), '#');
634
+ if ( ctype_digit( (string)$order_number ) ) {
635
+ // order_number == integer: use as starting point.
636
+ $invoice_number = $order_number;
637
+ } else {
638
+ // fallback: use order_id as starting point.
639
+ $invoice_number = $order_id;
640
+ }
641
+
642
+ } else {
643
+ $invoice_number = $next_invoice_number;
644
+ }
645
+
646
+ // reset invoice number yearly
647
+ if ( isset( $this->template_settings['yearly_reset_invoice_number'] ) ) {
648
+ $current_year = date("Y");
649
+ $last_invoice_year = get_option( 'wpo_wcpdf_last_invoice_year' );
650
+ // check first time use
651
+ if ( empty( $last_invoice_year ) ) {
652
+ $last_invoice_year = $current_year;
653
+ update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
654
+ }
655
+ // check if we need to reset
656
+ if ( $current_year != $last_invoice_year ) {
657
+ $invoice_number = 1;
658
+ update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
659
+ }
660
+ }
661
+ // die($invoice_number);
662
+
663
+ // invoice number logging
664
+ // $order_number = ltrim($this->order->get_order_number(), '#');
665
+ // $this->log( $order_id, "Invoice number {$invoice_number} set for order {$order_number} (id {$order_id})" );
666
+
667
+ update_post_meta($order_id, '_wcpdf_invoice_number', $invoice_number);
668
+ update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
669
+
670
+ // increase next_order_number
671
+ $update_args = array(
672
+ 'option_value' => $invoice_number + 1,
673
+ 'autoload' => 'yes',
674
+ );
675
+ $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => 'wpo_wcpdf_next_invoice_number' ) );
676
+ }
677
+
678
+ // store invoice_number in class object
679
+ $this->invoice_number = $invoice_number;
680
+
681
+ // store invoice number in _POST superglobal to prevent the number from being cleared in a save action
682
+ // (http://wordpress.org/support/topic/customer-invoice-selection-from-order-detail-page-doesnt-record-invoice-id?replies=1)
683
+ $_POST['_wcpdf_invoice_number'] = $invoice_number;
684
+
685
+ return $invoice_number;
686
+ }
687
+
688
+ public function get_invoice_number( $order_id ) {
689
+ // get invoice number from post meta
690
+ if ( $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true ) ) {
691
+ // check if we have already loaded this order
692
+ if ( $this->order->id == $order_id ) {
693
+ $order_number = $this->order->get_order_number();
694
+ $order_date = $this->order->order_date;
695
+ } else {
696
+ $order = new WC_Order( $order_id );
697
+ $order_number = $order->get_order_number();
698
+ $order_date = $order->order_date;
699
+ }
700
+
701
+ return apply_filters( 'wpo_wcpdf_invoice_number', $invoice_number, $order_number, $order_id, $order_date );
702
+ } else {
703
+ // no invoice number for this order
704
+ return false;
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Add invoice number to WC REST API
710
+ */
711
+ public function woocommerce_api_invoice_numer ( $data, $order ) {
712
+ if ( $invoice_number = $this->get_invoice_number( $order->id ) ) {
713
+ $data['wpo_wcpdf_invoice_number'] = $invoice_number;
714
+ } else {
715
+ $data['wpo_wcpdf_invoice_number'] = '';
716
+ }
717
+ return $data;
718
+ }
719
+
720
+ /**
721
+ * Reset invoice data for WooCommerce subscription renewal orders
722
+ * https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
723
+ */
724
+ public function woocommerce_subscriptions_renewal_order_created ( $renewal_order, $original_order, $product_id, $new_order_role ) {
725
+ $this->reset_invoice_data( $renewal_order->id );
726
+ return $renewal_order;
727
+ }
728
+
729
+ public function wcs_renewal_order_created ( $renewal_order, $subscription ) {
730
+ $this->reset_invoice_data( $renewal_order->id );
731
+ return $renewal_order;
732
+ }
733
+
734
+ public function reset_invoice_data ( $order_id ) {
735
+ // delete invoice number, invoice date & invoice exists meta
736
+ delete_post_meta( $order_id, '_wcpdf_invoice_number' );
737
+ delete_post_meta( $order_id, '_wcpdf_formatted_invoice_number' );
738
+ delete_post_meta( $order_id, '_wcpdf_invoice_date' );
739
+ delete_post_meta( $order_id, '_wcpdf_invoice_exists' );
740
+ }
741
+
742
+ public function format_invoice_number( $invoice_number, $order_number, $order_id, $order_date ) {
743
+ // get format settings
744
+ $formats['prefix'] = isset($this->template_settings['invoice_number_formatting_prefix'])?$this->template_settings['invoice_number_formatting_prefix']:'';
745
+ $formats['suffix'] = isset($this->template_settings['invoice_number_formatting_suffix'])?$this->template_settings['invoice_number_formatting_suffix']:'';
746
+ $formats['padding'] = isset($this->template_settings['invoice_number_formatting_padding'])?$this->template_settings['invoice_number_formatting_padding']:'';
747
+
748
+ // Replacements
749
+ $order_year = date_i18n( 'Y', strtotime( $order_date ) );
750
+ $order_month = date_i18n( 'm', strtotime( $order_date ) );
751
+ $invoice_date = get_post_meta($order_id,'_wcpdf_invoice_date',true);
752
+ $invoice_date = empty($invoice_date) ? current_time('mysql') : $invoice_date;
753
+ $invoice_year = date_i18n( 'Y', strtotime( $invoice_date ) );
754
+ $invoice_month = date_i18n( 'm', strtotime( $invoice_date ) );
755
+
756
+ foreach ($formats as $key => $value) {
757
+ $value = str_replace('[order_year]', $order_year, $value);
758
+ $value = str_replace('[order_month]', $order_month, $value);
759
+ $value = str_replace('[invoice_year]', $invoice_year, $value);
760
+ $value = str_replace('[invoice_month]', $invoice_month, $value);
761
+ $formats[$key] = $value;
762
+ }
763
+
764
+ // Padding
765
+ if ( ctype_digit( (string)$formats['padding'] ) ) {
766
+ $invoice_number = sprintf('%0'.$formats['padding'].'d', $invoice_number);
767
+ }
768
+
769
+ $formatted_invoice_number = $formats['prefix'] . $invoice_number . $formats['suffix'] ;
770
+
771
+ return $formatted_invoice_number;
772
+ }
773
+
774
+ public function get_display_number( $order_id ) {
775
+ if ( !isset($this->order->id) ) {
776
+ $this->order = new WC_Order ( $order_id );
777
+ }
778
+
779
+ if ( isset($this->template_settings['display_number']) && $this->template_settings['display_number'] == 'invoice_number' ) {
780
+ // use invoice number
781
+ $display_number = $this->get_invoice_number( $order_id );
782
+ // die($display_number);
783
+ } else {
784
+ // use order number
785
+ $display_number = ltrim($this->order->get_order_number(), '#');
786
+ }
787
+
788
+ return $display_number;
789
+ }
790
+
791
+ /**
792
+ * Return evaluated template contents
793
+ */
794
+ public function get_template( $file ) {
795
+ ob_start();
796
+ if (file_exists($file)) {
797
+ include($file);
798
+ }
799
+ return ob_get_clean();
800
+ }
801
+
802
+ /**
803
+ * Get the current order
804
+ */
805
+ public function get_order() {
806
+ return $this->order;
807
+ }
808
+
809
+ /**
810
+ * Get the current order items
811
+ */
812
+ public function get_order_items() {
813
+ global $woocommerce;
814
+ global $_product;
815
+
816
+ $items = $this->order->get_items();
817
+ $data_list = array();
818
+
819
+ if( sizeof( $items ) > 0 ) {
820
+ foreach ( $items as $item_id => $item ) {
821
+ // Array with data for the pdf template
822
+ $data = array();
823
+
824
+ // Set the item_id
825
+ $data['item_id'] = $item_id;
826
+
827
+ // Set the id
828
+ $data['product_id'] = $item['product_id'];
829
+ $data['variation_id'] = $item['variation_id'];
830
+
831
+ // Set item name
832
+ $data['name'] = $item['name'];
833
+
834
+ // Set item quantity
835
+ $data['quantity'] = $item['qty'];
836
+
837
+ // Set the line total (=after discount)
838
+ $data['line_total'] = $this->wc_price( $item['line_total'] );
839
+ $data['single_line_total'] = $this->wc_price( $item['line_total'] / max( 1, $item['qty'] ) );
840
+ $data['line_tax'] = $this->wc_price( $item['line_tax'] );
841
+ $data['single_line_tax'] = $this->wc_price( $item['line_tax'] / max( 1, $item['qty'] ) );
842
+
843
+ $line_tax_data = maybe_unserialize( isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '' );
844
+ $data['tax_rates'] = $this->get_tax_rate( $item['tax_class'], $item['line_total'], $item['line_tax'], $line_tax_data );
845
+
846
+ // Set the line subtotal (=before discount)
847
+ $data['line_subtotal'] = $this->wc_price( $item['line_subtotal'] );
848
+ $data['line_subtotal_tax'] = $this->wc_price( $item['line_subtotal_tax'] );
849
+ $data['ex_price'] = $this->get_formatted_item_price ( $item, 'total', 'excl' );
850
+ $data['price'] = $this->get_formatted_item_price ( $item, 'total' );
851
+ $data['order_price'] = $this->order->get_formatted_line_subtotal( $item ); // formatted according to WC settings
852
+
853
+ // Calculate the single price with the same rules as the formatted line subtotal (!)
854
+ // = before discount
855
+ $data['ex_single_price'] = $this->get_formatted_item_price ( $item, 'single', 'excl' );
856
+ $data['single_price'] = $this->get_formatted_item_price ( $item, 'single' );
857
+
858
+ // Pass complete item array
859
+ $data['item'] = $item;
860
+
861
+ // Create the product to display more info
862
+ $data['product'] = null;
863
+
864
+ $product = $this->order->get_product_from_item( $item );
865
+
866
+ // Checking fo existance, thanks to MDesigner0
867
+ if(!empty($product)) {
868
+ // Set the thumbnail id DEPRICATED (does not support thumbnail sizes), use thumbnail_path or thumbnail instead
869
+ $data['thumbnail_id'] = $this->get_thumbnail_id( $product );
870
+
871
+ // Thumbnail (full img tag)
872
+ $data['thumbnail'] = $this->get_thumbnail ( $product );
873
+
874
+ // Set the single price (turned off to use more consistent calculated price)
875
+ // $data['single_price'] = woocommerce_price ( $product->get_price() );
876
+
877
+ // Set item SKU
878
+ $data['sku'] = $product->get_sku();
879
+
880
+ // Set item weight
881
+ $data['weight'] = $product->get_weight();
882
+
883
+ // Set item dimensions
884
+ $data['dimensions'] = $product->get_dimensions();
885
+
886
+ // Pass complete product object
887
+ $data['product'] = $product;
888
+
889
+ }
890
+
891
+ // Set item meta
892
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
893
+ $meta = new WC_Order_Item_Meta( $item['item_meta'], $product );
894
+ } else {
895
+ // pass complete item for WC2.4+
896
+ $meta = new WC_Order_Item_Meta( $item, $product );
897
+ }
898
+
899
+ $data['meta'] = $meta->display( false, true );
900
+
901
+ $data_list[$item_id] = apply_filters( 'wpo_wcpdf_order_item_data', $data, $this->order );
902
+ }
903
+ }
904
+
905
+ return apply_filters( 'wpo_wcpdf_order_items_data', $data_list, $this->order );
906
+ }
907
+
908
+ /**
909
+ * Gets price - formatted for display.
910
+ *
911
+ * @access public
912
+ * @param mixed $item
913
+ * @return string
914
+ */
915
+ public function get_formatted_item_price ( $item, $type, $tax_display = '' ) {
916
+ $item_price = 0;
917
+ $divider = ($type == 'single' && $item['qty'] != 0 )?$item['qty']:1; //divide by 1 if $type is not 'single' (thus 'total')
918
+
919
+ if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) )
920
+ return;
921
+
922
+ if ( $tax_display == 'excl' ) {
923
+ $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item )) / $divider );
924
+ } else {
925
+ $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item, true )) / $divider );
926
+ }
927
+
928
+ return $item_price;
929
+ }
930
+
931
+ /**
932
+ * wrapper for wc2.1 depricated price function
933
+ */
934
+ public function wc_price( $price, $args = array() ) {
935
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
936
+ // WC 2.1 or newer is used
937
+ $args['currency'] = $this->order->get_order_currency();
938
+ $formatted_price = wc_price( $price, $args );
939
+ } else {
940
+ $formatted_price = woocommerce_price( $price );
941
+ }
942
+
943
+ return $formatted_price;
944
+ }
945
+
946
+ /**
947
+ * Get the tax rates/percentages for a given tax class
948
+ * @param string $tax_class tax class slug
949
+ * @return string $tax_rates imploded list of tax rates
950
+ */
951
+ public function get_tax_rate( $tax_class, $line_total, $line_tax, $line_tax_data = '' ) {
952
+ if ( $line_tax == 0 ) {
953
+ return '-'; // no need to determine tax rate...
954
+ }
955
+
956
+ // first try the easy wc2.2 way, using line_tax_data
957
+ if ( !empty( $line_tax_data ) && isset($line_tax_data['total']) ) {
958
+ $tax_rates = array();
959
+
960
+ $line_taxes = $line_tax_data['total'];
961
+ foreach ( $line_taxes as $tax_id => $tax ) {
962
+ if ( !empty($tax) && $tax != 0 ) {
963
+ $tax_rates[] = $this->get_tax_rate_by_id( $tax_id ) . ' %';
964
+ }
965
+ }
966
+
967
+ $tax_rates = implode(' ,', $tax_rates );
968
+ return $tax_rates;
969
+ }
970
+
971
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 && !apply_filters( 'wpo_wcpdf_calculate_tax_rate', false ) ) {
972
+ // WC 2.1 or newer is used
973
+
974
+ // if (empty($tax_class))
975
+ // $tax_class = 'standard';// does not appear to work anymore - get_rates does accept an empty tax_class though!
976
+
977
+ $tax = new WC_Tax();
978
+ $taxes = $tax->get_rates( $tax_class );
979
+
980
+ $tax_rates = array();
981
+
982
+ foreach ($taxes as $tax) {
983
+ $tax_rates[$tax['label']] = round( $tax['rate'], 2 ).' %';
984
+ }
985
+
986
+ if (empty($tax_rates)) {
987
+ // one last try: manually calculate
988
+ if ( $line_total != 0) {
989
+ $tax_rates[] = round( ($line_tax / $line_total)*100, 1 ).' %';
990
+ } else {
991
+ $tax_rates[] = '-';
992
+ }
993
+ }
994
+
995
+ $tax_rates = implode(' ,', $tax_rates );
996
+ } else {
997
+ // Backwards compatibility/fallback: calculate tax from line items
998
+ if ( $line_total != 0) {
999
+ $tax_rates = round( ($line_tax / $line_total)*100, 1 ).' %';
1000
+ } else {
1001
+ $tax_rates = '-';
1002
+ }
1003
+ }
1004
+
1005
+ return $tax_rates;
1006
+ }
1007
+
1008
+ /**
1009
+ * Returns the percentage rate (float) for a given tax rate ID.
1010
+ * @param int $rate_id woocommerce tax rate id
1011
+ * @return float $rate percentage rate
1012
+ */
1013
+ public function get_tax_rate_by_id( $rate_id ) {
1014
+ global $wpdb;
1015
+ $rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) );
1016
+ return (float) $rate;
1017
+ }
1018
+
1019
+ /**
1020
+ * Returns a an array with rate_id => tax rate data (array) of all tax rates in woocommerce
1021
+ * @return array $tax_rate_ids keyed by id
1022
+ */
1023
+ public function get_tax_rate_ids() {
1024
+ global $wpdb;
1025
+ $rates = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates" );
1026
+
1027
+ $tax_rate_ids = array();
1028
+ foreach ($rates as $rate) {
1029
+ // var_dump($rate->tax_rate_id);
1030
+ // die($rate);
1031
+ $rate_id = $rate->tax_rate_id;
1032
+ unset($rate->tax_rate_id);
1033
+ $tax_rate_ids[$rate_id] = (array) $rate;
1034
+ }
1035
+
1036
+ return $tax_rate_ids;
1037
+ }
1038
+
1039
+ /**
1040
+ * Get order custom field
1041
+ */
1042
+ public function get_order_field( $field ) {
1043
+ if( isset( $this->get_order()->order_custom_fields[$field] ) ) {
1044
+ return $this->get_order()->order_custom_fields[$field][0];
1045
+ }
1046
+ return;
1047
+ }
1048
+
1049
+ /**
1050
+ * Returns the main product image ID
1051
+ * Adapted from the WC_Product class
1052
+ *
1053
+ * @access public
1054
+ * @return string
1055
+ */
1056
+ public function get_thumbnail_id ( $product ) {
1057
+ // DEPRICATED (does not support thumbnail sizes)
1058
+ global $woocommerce;
1059
+
1060
+ if ( $product->variation_id && has_post_thumbnail( $product->variation_id ) ) {
1061
+ $thumbnail_id = get_post_thumbnail_id ( $product->variation_id );
1062
+ } elseif ( has_post_thumbnail( $product->id ) ) {
1063
+ $thumbnail_id = get_post_thumbnail_id ( $product->id );
1064
+ } elseif ( ( $parent_id = wp_get_post_parent_id( $product->id ) ) && has_post_thumbnail( $parent_id ) ) {
1065
+ $thumbnail_id = get_post_thumbnail_id ( $parent_id );
1066
+ } else {
1067
+ $thumbnail_id = $woocommerce->plugin_url() . '/assets/images/placeholder.png';
1068
+ }
1069
+
1070
+ return $thumbnail_id;
1071
+ }
1072
+
1073
+ public function get_thumbnail ( $product ) {
1074
+ // Get default WooCommerce img tag (url/http)
1075
+ $size = apply_filters( 'wpo_wcpdf_thumbnail_size', 'shop_thumbnail' );
1076
+ $thumbnail_img_tag_url = $product->get_image( $size, array( 'title' => '' ) );
1077
+
1078
+ // Extract the url from img
1079
+ preg_match('/<img(.*)src(.*)=(.*)"(.*)"/U', $thumbnail_img_tag_url, $thumbnail_url );
1080
+ // convert url to path
1081
+ $thumbnail_path = str_replace( get_site_url() . '/', ABSPATH, array_pop($thumbnail_url));
1082
+
1083
+ // Thumbnail (full img tag)
1084
+ if (apply_filters('wpo_wcpdf_use_path', true) && file_exists($thumbnail_path)) {
1085
+ // load img with server path by default
1086
+ $thumbnail = sprintf('<img width="90" height="90" src="%s" class="attachment-shop_thumbnail wp-post-image">', $thumbnail_path );
1087
+ } else {
1088
+ // load img with http url when filtered
1089
+ $thumbnail = $thumbnail_img_tag_url;
1090
+ }
1091
+
1092
+ // die($thumbnail);
1093
+
1094
+ return $thumbnail;
1095
+ }
1096
+
1097
+ public function add_product_bundles_classes ( $classes, $template_type, $order, $item_id = '' ) {
1098
+ if ( empty($item_id) ) {
1099
+ // get item id from classes (backwards compatibility fix)
1100
+ $class_array = explode(' ', $classes);
1101
+ foreach ($class_array as $class) {
1102
+ if (is_numeric($class)) {
1103
+ $item_id = $class;
1104
+ break;
1105
+ }
1106
+ }
1107
+
1108
+ // if still empty, we lost the item id somewhere :(
1109
+ if (empty($item_id)) {
1110
+ return $classes;
1111
+ }
1112
+ }
1113
+
1114
+ $item_meta = $order->get_item_meta( $item_id );
1115
+
1116
+ if (isset($item_meta['_bundled_by'])) {
1117
+ $classes = $classes . ' bundled-item';
1118
+
1119
+ // check bundled item visibility
1120
+ if ( ! empty( $item_meta[ '_bundled_item_hidden' ] ) ) {
1121
+ $classes = $classes . ' hidden';
1122
+ }
1123
+
1124
+ return $classes;
1125
+ } elseif (isset($item_meta['_bundled_items'])) {
1126
+ return $classes . ' product-bundle';
1127
+ }
1128
+
1129
+ return $classes;
1130
+ }
1131
+
1132
+ public function add_chained_product_class ( $classes, $template_type, $order, $item_id = '' ) {
1133
+ if ( empty($item_id) ) {
1134
+ // get item id from classes (backwards compatibility fix)
1135
+ $class_array = explode(' ', $classes);
1136
+ foreach ($class_array as $class) {
1137
+ if (is_numeric($class)) {
1138
+ $item_id = $class;
1139
+ break;
1140
+ }
1141
+ }
1142
+
1143
+ // if still empty, we lost the item id somewhere :(
1144
+ if (empty($item_id)) {
1145
+ return $classes;
1146
+ }
1147
+ }
1148
+
1149
+ $item_meta = $order->get_item_meta( $item_id );
1150
+
1151
+ if (isset($item_meta['_chained_product_of'])) {
1152
+ return $classes . ' chained-product';
1153
+ }
1154
+
1155
+ return $classes;
1156
+ }
1157
+
1158
+ /**
1159
+ * Filter plugin strings with qTranslate-X
1160
+ */
1161
+ public function qtranslatex_filters() {
1162
+ $use_filters = array(
1163
+ 'wpo_wcpdf_shop_name' => 20,
1164
+ 'wpo_wcpdf_shop_address' => 20,
1165
+ 'wpo_wcpdf_footer' => 20,
1166
+ 'wpo_wcpdf_order_items' => 20,
1167
+ 'wpo_wcpdf_payment_method' => 20,
1168
+ 'wpo_wcpdf_shipping_method' => 20,
1169
+ 'wpo_wcpdf_extra_1' => 20,
1170
+ 'wpo_wcpdf_extra_2' => 20,
1171
+ 'wpo_wcpdf_extra_3' => 20,
1172
+ );
1173
+
1174
+ foreach ( $use_filters as $name => $priority ) {
1175
+ add_filter( $name, 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage', $priority );
1176
+ }
1177
+ }
1178
+
1179
+ public function enable_debug () {
1180
+ error_reporting( E_ALL );
1181
+ ini_set( 'display_errors', 1 );
1182
+ }
1183
+
1184
+ /**
1185
+ * Log messages
1186
+ */
1187
+
1188
+ public function log( $order_id, $message ) {
1189
+ $current_date_time = date("Y-m-d H:i:s");
1190
+ $message = $order_id . ' ' . $current_date_time .' ' .$message ."\n";
1191
+ $file = $this->tmp_path() . 'log.txt';
1192
+
1193
+ file_put_contents($file, $message, FILE_APPEND);
1194
+ }
1195
+ }
1196
+
1197
+ }
languages/wpo_wcpdf-fr_FR.mo CHANGED
Binary file
languages/wpo_wcpdf-fr_FR.po CHANGED
@@ -3,7 +3,7 @@ msgstr ""
3
  "Project-Id-Version: WooCommerce PDF Invoices & Packing Slips v1.3.2\n"
4
  "Report-Msgid-Bugs-To: \n"
5
  "POT-Creation-Date: 2015-10-06 14:34+0200\n"
6
- "PO-Revision-Date: 2015-10-06 14:34+0200\n"
7
  "Last-Translator: Serge Labrosse <serge.labrosse@gmail.com>\n"
8
  "Language-Team: WP Overnight <support@wpovernight.com>\n"
9
  "Language: fr_FR\n"
@@ -11,7 +11,7 @@ msgstr ""
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
  "Plural-Forms: nplurals=2; plural=n>1;\n"
14
- "X-Generator: Poedit 1.8.5\n"
15
  "X-Poedit-SourceCharset: UTF-8\n"
16
  "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;"
17
  "_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2\n"
@@ -134,14 +134,16 @@ msgstr "Interface"
134
  #: includes/class-wcpdf-settings.php:298
135
  msgid "Allow My Account invoice download"
136
  msgstr ""
 
 
137
 
138
  #: includes/class-wcpdf-settings.php:306
139
  msgid "Only when an invoice is already created/emailed"
140
- msgstr ""
141
 
142
  #: includes/class-wcpdf-settings.php:307
143
  msgid "Only for specific order statuses (define below)"
144
- msgstr ""
145
 
146
  #: includes/class-wcpdf-settings.php:308
147
  msgid "Always"
@@ -149,7 +151,7 @@ msgstr "Toujours"
149
 
150
  #: includes/class-wcpdf-settings.php:309
151
  msgid "Never"
152
- msgstr ""
153
 
154
  #: includes/class-wcpdf-settings.php:324
155
  msgid "Enable invoice number column in the orders list"
@@ -246,7 +248,7 @@ msgstr "Afficher la date de la facture"
246
 
247
  #: includes/class-wcpdf-settings.php:524
248
  msgid "Display built-in sequential invoice number"
249
- msgstr ""
250
 
251
  #: includes/class-wcpdf-settings.php:537
252
  msgid "Next invoice number (without prefix/suffix etc.)"
@@ -288,7 +290,7 @@ msgstr "Suffixe"
288
 
289
  #: includes/class-wcpdf-settings.php:570
290
  msgid "Padding"
291
- msgstr ""
292
 
293
  #: includes/class-wcpdf-settings.php:572
294
  msgid "enter the number of digits here - enter \"6\" to display 42 as 000042"
@@ -357,26 +359,30 @@ msgstr "Paramètres de débogage"
357
 
358
  #: includes/class-wcpdf-settings.php:722
359
  msgid "Enable debug output"
360
- msgstr ""
361
 
362
  #: includes/class-wcpdf-settings.php:729
363
  msgid ""
364
  "Enable this option to output plugin errors if you're getting a blank page or "
365
  "other PDF generation issues"
366
  msgstr ""
 
 
367
 
368
  #: includes/class-wcpdf-settings.php:735
369
  msgid "Output to HTML"
370
- msgstr ""
371
 
372
  #: includes/class-wcpdf-settings.php:742
373
  msgid ""
374
  "Send the template output as HTML to the browser instead of creating a PDF."
375
  msgstr ""
 
 
376
 
377
  #: includes/class-wcpdf-settings.php:748
378
  msgid "Use old tmp folder"
379
- msgstr ""
380
 
381
  #: includes/class-wcpdf-settings.php:755
382
  msgid ""
@@ -384,6 +390,10 @@ msgid ""
384
  "plugin folder. This setting is only intended for backwards compatibility, "
385
  "not recommended on new installs!"
386
  msgstr ""
 
 
 
 
387
 
388
  #: includes/class-wcpdf-settings.php:1097
389
  msgid "Image resolution"
@@ -435,11 +445,11 @@ msgstr "Créer un PDF"
435
 
436
  #: includes/class-wcpdf-writepanels.php:226
437
  msgid "PDF Invoice data"
438
- msgstr ""
439
 
440
  #: includes/class-wcpdf-writepanels.php:279
441
  msgid "Invoice Number (unformatted!)"
442
- msgstr ""
443
 
444
  #: includes/class-wcpdf-writepanels.php:287 templates/pdf/Simple/invoice.php:55
445
  msgid "Invoice Date:"
@@ -447,11 +457,11 @@ msgstr "Date de la facture :"
447
 
448
  #: includes/class-wcpdf-writepanels.php:289
449
  msgid "h"
450
- msgstr ""
451
 
452
  #: includes/class-wcpdf-writepanels.php:289
453
  msgid "m"
454
- msgstr ""
455
 
456
  #: includes/wcpdf-extensions.php:15
457
  msgid "Check out these premium extensions!"
@@ -470,28 +480,35 @@ msgid ""
470
  "Supercharge WooCommerce PDF Invoices & Packing Slips with the following "
471
  "features:"
472
  msgstr ""
 
473
 
474
  #: includes/wcpdf-extensions.php:27
475
  msgid "Email/print/download <b>PDF Credit Notes & Proforma invoices</b>"
476
- msgstr ""
477
 
478
  #: includes/wcpdf-extensions.php:28
479
  msgid ""
480
  "Send out a separate <b>notification email</b> with (or without) PDF invoices/"
481
  "packing slips, for example to a drop-shipper or a supplier."
482
  msgstr ""
 
 
483
 
484
  #: includes/wcpdf-extensions.php:29
485
  msgid ""
486
  "Attach <b>up to 3 static files</b> (for example a terms & conditions "
487
  "document) to the WooCommerce emails of your choice."
488
  msgstr ""
 
 
489
 
490
  #: includes/wcpdf-extensions.php:30
491
  msgid ""
492
  "Use <b>separate numbering systems</b> and/or format for proforma invoices "
493
  "and credit notes or utilize the main invoice numbering system"
494
  msgstr ""
 
 
495
 
496
  #: includes/wcpdf-extensions.php:31
497
  msgid ""
@@ -499,14 +516,17 @@ msgid ""
499
  "additional custom fields, font sizes etc. without the need to create a "
500
  "custom template."
501
  msgstr ""
 
 
 
502
 
503
  #: includes/wcpdf-extensions.php:32
504
  msgid "Use the plugin in multilingual <b>WPML</b> setups"
505
- msgstr ""
506
 
507
  #: includes/wcpdf-extensions.php:34
508
  msgid "Get WooCommerce PDF Invoices & Packing Slips Professional!"
509
- msgstr ""
510
 
511
  #: includes/wcpdf-extensions.php:42
512
  msgid "Upload all invoices automatically to your dropbox"
@@ -519,10 +539,14 @@ msgid ""
519
  "customers to Dropbox. The best way to keep your invoice administration up to "
520
  "date!"
521
  msgstr ""
 
 
 
 
522
 
523
  #: includes/wcpdf-extensions.php:49
524
  msgid "Get WooCommerce PDF Invoices & Packing Slips to dropbox!"
525
- msgstr ""
526
 
527
  #: includes/wcpdf-extensions.php:61
528
  msgid ""
@@ -537,6 +561,8 @@ msgid ""
537
  "Check out the WooCommerce Automatic Order Printing extension from our "
538
  "partners at Simba Hosting"
539
  msgstr ""
 
 
540
 
541
  #: includes/wcpdf-extensions.php:68
542
  msgid "WooCommerce Automatic Order Printing"
@@ -544,22 +570,24 @@ msgstr ""
544
 
545
  #: includes/wcpdf-extensions.php:82
546
  msgid "Advanced, customizable templates"
547
- msgstr ""
548
 
549
  #: includes/wcpdf-extensions.php:85
550
  msgid ""
551
  "Completely customize the invoice contents (prices, taxes, thumbnails) to "
552
  "your needs with a drag & drop customizer"
553
  msgstr ""
 
 
554
 
555
  #: includes/wcpdf-extensions.php:86
556
  msgid "Two extra stylish premade templates (Modern & Business)"
557
- msgstr ""
558
 
559
  #: includes/wcpdf-extensions.php:87
560
  #, php-format
561
  msgid "Check out the Premium PDF Invoice & Packing Slips templates at %s."
562
- msgstr ""
563
 
564
  #: includes/wcpdf-extensions.php:88
565
  #, php-format
@@ -656,7 +684,7 @@ msgstr "Méthode de livraison"
656
  #: woocommerce-pdf-invoices-packingslips.php:693
657
  #, php-format
658
  msgid "(Includes %s)"
659
- msgstr ""
660
 
661
  #: woocommerce-pdf-invoices-packingslips.php:714
662
  msgid "Subtotal"
3
  "Project-Id-Version: WooCommerce PDF Invoices & Packing Slips v1.3.2\n"
4
  "Report-Msgid-Bugs-To: \n"
5
  "POT-Creation-Date: 2015-10-06 14:34+0200\n"
6
+ "PO-Revision-Date: 2016-04-01 18:22+0200\n"
7
  "Last-Translator: Serge Labrosse <serge.labrosse@gmail.com>\n"
8
  "Language-Team: WP Overnight <support@wpovernight.com>\n"
9
  "Language: fr_FR\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
  "Plural-Forms: nplurals=2; plural=n>1;\n"
14
+ "X-Generator: Poedit 1.8.7\n"
15
  "X-Poedit-SourceCharset: UTF-8\n"
16
  "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;"
17
  "_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2\n"
134
  #: includes/class-wcpdf-settings.php:298
135
  msgid "Allow My Account invoice download"
136
  msgstr ""
137
+ "Autoriser le téléchargement des factures à partir de l'interface \"Mon compte"
138
+ "\""
139
 
140
  #: includes/class-wcpdf-settings.php:306
141
  msgid "Only when an invoice is already created/emailed"
142
+ msgstr "Seulement lorsque la facture est déjà créée/envoyée par email"
143
 
144
  #: includes/class-wcpdf-settings.php:307
145
  msgid "Only for specific order statuses (define below)"
146
+ msgstr "Uniquement pour les statuts de commandes suivants"
147
 
148
  #: includes/class-wcpdf-settings.php:308
149
  msgid "Always"
151
 
152
  #: includes/class-wcpdf-settings.php:309
153
  msgid "Never"
154
+ msgstr "Jamais"
155
 
156
  #: includes/class-wcpdf-settings.php:324
157
  msgid "Enable invoice number column in the orders list"
248
 
249
  #: includes/class-wcpdf-settings.php:524
250
  msgid "Display built-in sequential invoice number"
251
+ msgstr "Afficher le numéro de facture intégré"
252
 
253
  #: includes/class-wcpdf-settings.php:537
254
  msgid "Next invoice number (without prefix/suffix etc.)"
290
 
291
  #: includes/class-wcpdf-settings.php:570
292
  msgid "Padding"
293
+ msgstr "Décalage"
294
 
295
  #: includes/class-wcpdf-settings.php:572
296
  msgid "enter the number of digits here - enter \"6\" to display 42 as 000042"
359
 
360
  #: includes/class-wcpdf-settings.php:722
361
  msgid "Enable debug output"
362
+ msgstr "Activer les résultats de débug"
363
 
364
  #: includes/class-wcpdf-settings.php:729
365
  msgid ""
366
  "Enable this option to output plugin errors if you're getting a blank page or "
367
  "other PDF generation issues"
368
  msgstr ""
369
+ "Activer cette option pour publier les erreurs du plugin tel que si obtenez "
370
+ "une page blanche ou des problèmes de génération de PDF"
371
 
372
  #: includes/class-wcpdf-settings.php:735
373
  msgid "Output to HTML"
374
+ msgstr "Résultats en HTML"
375
 
376
  #: includes/class-wcpdf-settings.php:742
377
  msgid ""
378
  "Send the template output as HTML to the browser instead of creating a PDF."
379
  msgstr ""
380
+ "Envoyer un modèle de résultats en HTML dans le navigateur au lieu de créer "
381
+ "un PDF"
382
 
383
  #: includes/class-wcpdf-settings.php:748
384
  msgid "Use old tmp folder"
385
+ msgstr "Utiliser le fichier temporaire"
386
 
387
  #: includes/class-wcpdf-settings.php:755
388
  msgid ""
390
  "plugin folder. This setting is only intended for backwards compatibility, "
391
  "not recommended on new installs!"
392
  msgstr ""
393
+ "Avant la version 1.5 de PDF Invoices, les fichiers temporaires étaient "
394
+ "stockés dans le dossier du plugin. Ce paramètre est requis seulement pour "
395
+ "les versions antérieures compatibles, non recommandé sur les nouvelles "
396
+ "installations."
397
 
398
  #: includes/class-wcpdf-settings.php:1097
399
  msgid "Image resolution"
445
 
446
  #: includes/class-wcpdf-writepanels.php:226
447
  msgid "PDF Invoice data"
448
+ msgstr "Données de Facture PDF"
449
 
450
  #: includes/class-wcpdf-writepanels.php:279
451
  msgid "Invoice Number (unformatted!)"
452
+ msgstr "Numéro de facture (non formaté !)"
453
 
454
  #: includes/class-wcpdf-writepanels.php:287 templates/pdf/Simple/invoice.php:55
455
  msgid "Invoice Date:"
457
 
458
  #: includes/class-wcpdf-writepanels.php:289
459
  msgid "h"
460
+ msgstr "h"
461
 
462
  #: includes/class-wcpdf-writepanels.php:289
463
  msgid "m"
464
+ msgstr "m"
465
 
466
  #: includes/wcpdf-extensions.php:15
467
  msgid "Check out these premium extensions!"
480
  "Supercharge WooCommerce PDF Invoices & Packing Slips with the following "
481
  "features:"
482
  msgstr ""
483
+ "Boostez WooCommerce PDF Invoices & Packing Slips avec les options suivantes :"
484
 
485
  #: includes/wcpdf-extensions.php:27
486
  msgid "Email/print/download <b>PDF Credit Notes & Proforma invoices</b>"
487
+ msgstr "Envoyer/imprimer/télécharger les <b> Avoirs et Devis PDF</b>"
488
 
489
  #: includes/wcpdf-extensions.php:28
490
  msgid ""
491
  "Send out a separate <b>notification email</b> with (or without) PDF invoices/"
492
  "packing slips, for example to a drop-shipper or a supplier."
493
  msgstr ""
494
+ "Envoyer séparément <b>la notification email</b> avec (ou sans) PDF invoices/"
495
+ "packing slips, par exemple à un transporteur ou un fournisseur."
496
 
497
  #: includes/wcpdf-extensions.php:29
498
  msgid ""
499
  "Attach <b>up to 3 static files</b> (for example a terms & conditions "
500
  "document) to the WooCommerce emails of your choice."
501
  msgstr ""
502
+ "Joindre<b>jusqu'à 3 fichiers fixes</b> (par exemple les conditions générales "
503
+ "de ventes)aux emails WooCommerce de votre choix."
504
 
505
  #: includes/wcpdf-extensions.php:30
506
  msgid ""
507
  "Use <b>separate numbering systems</b> and/or format for proforma invoices "
508
  "and credit notes or utilize the main invoice numbering system"
509
  msgstr ""
510
+ "Utiliser <b>une numérotation séparée</b> et/ou un format pour les Devis et "
511
+ "Avoirs ou utiliser la numérotation principale du système."
512
 
513
  #: includes/wcpdf-extensions.php:31
514
  msgid ""
516
  "additional custom fields, font sizes etc. without the need to create a "
517
  "custom template."
518
  msgstr ""
519
+ "<b>Personnaliser le format de l'adresse de livraison et de facturation</b> "
520
+ "pour ajouter des champs personnalisés, taille de police, etc. sans créer de "
521
+ "modèle personnalisé."
522
 
523
  #: includes/wcpdf-extensions.php:32
524
  msgid "Use the plugin in multilingual <b>WPML</b> setups"
525
+ msgstr "Utiliser l'extension en configuration multilingue <b>WPML</b>"
526
 
527
  #: includes/wcpdf-extensions.php:34
528
  msgid "Get WooCommerce PDF Invoices & Packing Slips Professional!"
529
+ msgstr "Achetez WooCommerce PDF Invoices & Packing Slips Professional!"
530
 
531
  #: includes/wcpdf-extensions.php:42
532
  msgid "Upload all invoices automatically to your dropbox"
539
  "customers to Dropbox. The best way to keep your invoice administration up to "
540
  "date!"
541
  msgstr ""
542
+ "Cette extension télécharge normalement toutes les factures (et autres "
543
+ "documents PDF pour l'extension professionnelle) envoyés par email dans votre "
544
+ "compte Dropbox. La meilleure façon de conserver vos documents administratif "
545
+ "à jour !"
546
 
547
  #: includes/wcpdf-extensions.php:49
548
  msgid "Get WooCommerce PDF Invoices & Packing Slips to dropbox!"
549
+ msgstr "Achetez WooCommerce PDF Invoices & Packing Slips to dropbox!"
550
 
551
  #: includes/wcpdf-extensions.php:61
552
  msgid ""
561
  "Check out the WooCommerce Automatic Order Printing extension from our "
562
  "partners at Simba Hosting"
563
  msgstr ""
564
+ "Découvrez WooCommerce Automatic Order Printing de notre partenaire Simba "
565
+ "Hosting"
566
 
567
  #: includes/wcpdf-extensions.php:68
568
  msgid "WooCommerce Automatic Order Printing"
570
 
571
  #: includes/wcpdf-extensions.php:82
572
  msgid "Advanced, customizable templates"
573
+ msgstr "Modèles avancés personnalisables"
574
 
575
  #: includes/wcpdf-extensions.php:85
576
  msgid ""
577
  "Completely customize the invoice contents (prices, taxes, thumbnails) to "
578
  "your needs with a drag & drop customizer"
579
  msgstr ""
580
+ "Adaptez intégralement le contenus des factures (prix, taxes, miniatures) à "
581
+ "vos besoins avec un système de \"glisser-déposer\""
582
 
583
  #: includes/wcpdf-extensions.php:86
584
  msgid "Two extra stylish premade templates (Modern & Business)"
585
+ msgstr "Deux modèles supplémentaires élégant prédéfinis (Moderne & Business)"
586
 
587
  #: includes/wcpdf-extensions.php:87
588
  #, php-format
589
  msgid "Check out the Premium PDF Invoice & Packing Slips templates at %s."
590
+ msgstr "Consultez les modèles Prémium PDF Invoice & Packing Slips ici %s."
591
 
592
  #: includes/wcpdf-extensions.php:88
593
  #, php-format
684
  #: woocommerce-pdf-invoices-packingslips.php:693
685
  #, php-format
686
  msgid "(Includes %s)"
687
+ msgstr "(Inclus %s)"
688
 
689
  #: woocommerce-pdf-invoices-packingslips.php:714
690
  msgid "Subtotal"
languages/wpo_wcpdf-hr.mo ADDED
Binary file
languages/wpo_wcpdf-hr.po ADDED
@@ -0,0 +1,747 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: WooCommerce PDF Invoices & Packing Slips\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2016-02-02 15:18+0100\n"
6
+ "PO-Revision-Date: Sun Mar 27 2016 16:13:01 GMT+0200\n"
7
+ "Last-Translator: spineict <admin@spine-ict.hr>\n"
8
+ "Language-Team: WP Overnight <support@wpovernight.com>\n"
9
+ "Language: Croatian\n"
10
+ "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10 >= 2 && "
11
+ "n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Generator: Loco - https://localise.biz/\n"
17
+ "X-Poedit-Basepath: ..\n"
18
+ "X-Poedit-KeywordsList: _:1;gettext:1;dgettext:2;ngettext:1,2;dngettext:2,3;"
19
+ "__:1;_e:1;_c:1;_n:1,2;_n_noop:1,2;_nc:1,2;__ngettext:1,2;__ngettext_noop:1,2;"
20
+ "_x:1,2c;_ex:1,2c;_nx:1,2,4c;_nx_noop:1,2,3c;_n_js:1,2;_nx_js:1,2,3c;"
21
+ "esc_attr__:1;esc_html__:1;esc_attr_e:1;esc_html_e:1;esc_attr_x:1,2c;"
22
+ "esc_html_x:1,2c;comments_number_link:2,3;t:1;st:1;trans:1;transChoice:1,2\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
+ "X-Loco-Target-Locale: hr_HR"
25
+
26
+ #. Name of the plugin
27
+ msgid "WooCommerce PDF Invoices & Packing Slips"
28
+ msgstr "WooCOmmerce PDF Računi & Paketni Slipovi"
29
+
30
+ #. URI of the plugin
31
+ msgid "http://www.wpovernight.com"
32
+ msgstr "http://www.wpovernight.com"
33
+
34
+ #. Description of the plugin
35
+ msgid "Create, print & email PDF invoices & packing slips for WooCommerce orders."
36
+ msgstr ""
37
+ "Izradi, Ispiši & pošalji E-mailom Račune & paketne slipove za narudžbe putem "
38
+ "WooCommerce-a."
39
+
40
+ #. Author of the plugin
41
+ msgid "Ewout Fernhout"
42
+ msgstr "Ewout Fernhout"
43
+
44
+ #: ../woocommerce-pdf-invoices-packingslips.php:123
45
+ #, php-format
46
+ msgid ""
47
+ "WooCommerce PDF Invoices & Packing Slips requires %sWooCommerce%s to be "
48
+ "installed & activated!"
49
+ msgstr ""
50
+ "WooCommerce PDF Računi & Slipovi za pakete zahtjevaju instalaciju i "
51
+ "aktivaciju %sWooCommerce%-a"
52
+
53
+ #: ../woocommerce-pdf-invoices-packingslips.php:226 ../includes/class-wcpdf-
54
+ #: settings.php:470 ../includes/class-wcpdf-writepanels.php:286 ..
55
+ #: templates/pdf/Simple/invoice.php:9 ../templates/pdf/Simple/invoice.php:21
56
+ msgid "Invoice"
57
+ msgstr "Račun"
58
+
59
+ #: ../woocommerce-pdf-invoices-packingslips.php:229 ../includes/class-wcpdf-
60
+ #: settings.php:617 ../templates/pdf/Simple/packing-slip.php:9 ..
61
+ #: templates/pdf/Simple/packing-slip.php:21
62
+ msgid "Packing Slip"
63
+ msgstr "Paketni slip"
64
+
65
+ #: ../woocommerce-pdf-invoices-packingslips.php:373 ../woocommerce-pdf-invoices-
66
+ #: packingslips.php:434
67
+ msgid "N/A"
68
+ msgstr "Ništa"
69
+
70
+ #: ../woocommerce-pdf-invoices-packingslips.php:529
71
+ msgid "Payment method"
72
+ msgstr "Metoda plaćanja"
73
+
74
+ #: ../woocommerce-pdf-invoices-packingslips.php:548
75
+ msgid "Shipping method"
76
+ msgstr "Metoda dostave"
77
+
78
+ #: ../woocommerce-pdf-invoices-packingslips.php:707
79
+ #, php-format
80
+ msgid "(Includes %s)"
81
+ msgstr "(Uključujući %s)"
82
+
83
+ #: ../woocommerce-pdf-invoices-packingslips.php:728
84
+ msgid "Subtotal"
85
+ msgstr "Ukupno (subtotal)"
86
+
87
+ #: ../woocommerce-pdf-invoices-packingslips.php:750
88
+ msgid "Shipping"
89
+ msgstr "Dostava"
90
+
91
+ #: ../woocommerce-pdf-invoices-packingslips.php:813
92
+ msgid "Discount"
93
+ msgstr "Popust"
94
+
95
+ #: ../woocommerce-pdf-invoices-packingslips.php:854
96
+ msgid "VAT"
97
+ msgstr "PDV"
98
+
99
+ #: ../woocommerce-pdf-invoices-packingslips.php:855
100
+ msgid "Tax rate"
101
+ msgstr "Visina poreza"
102
+
103
+ #: ../woocommerce-pdf-invoices-packingslips.php:892
104
+ msgid "Total ex. VAT"
105
+ msgstr "Ukupno bez PDV-a"
106
+
107
+ #: ../woocommerce-pdf-invoices-packingslips.php:895
108
+ msgid "Total"
109
+ msgstr "Ukupno"
110
+
111
+ #: ../includes/class-wcpdf-settings.php:37 ../includes/class-wcpdf-settings.php:
112
+ #: 38 ../includes/class-wcpdf-writepanels.php:32
113
+ msgid "PDF Invoices"
114
+ msgstr "PDF Račun"
115
+
116
+ #: ../includes/class-wcpdf-settings.php:79
117
+ msgid "Settings"
118
+ msgstr "Postavke"
119
+
120
+ #: ../includes/class-wcpdf-settings.php:101
121
+ msgid "General"
122
+ msgstr "Općenito"
123
+
124
+ #: ../includes/class-wcpdf-settings.php:102
125
+ msgid "Template"
126
+ msgstr "Predložak"
127
+
128
+ #: ../includes/class-wcpdf-settings.php:107
129
+ msgid "Status"
130
+ msgstr "Status"
131
+
132
+ #: ../includes/class-wcpdf-settings.php:119
133
+ msgid "WooCommerce PDF Invoices"
134
+ msgstr "Woocommerce PDF Računi"
135
+
136
+ #: ../includes/class-wcpdf-settings.php:188
137
+ msgid "General settings"
138
+ msgstr "Opće postavke"
139
+
140
+ #: ../includes/class-wcpdf-settings.php:195
141
+ msgid "How do you want to view the PDF?"
142
+ msgstr "Što želite učiniti s PDF-om?"
143
+
144
+ #: ../includes/class-wcpdf-settings.php:203
145
+ msgid "Download the PDF"
146
+ msgstr "Preuzmi PDF "
147
+
148
+ #: ../includes/class-wcpdf-settings.php:204
149
+ msgid "Open the PDF in a new browser tab/window"
150
+ msgstr "Otvorite PDF u novoj kartici preglednika / u novom prozoru"
151
+
152
+ #: ../includes/class-wcpdf-settings.php:213
153
+ msgid "Admin New Order email"
154
+ msgstr "e-mail obavijest administratoru o novoj narudžbi"
155
+
156
+ #: ../includes/class-wcpdf-settings.php:214
157
+ msgid "Customer Processing Order email"
158
+ msgstr "e-mail obavijest klijentu o postupku obrade narudžbe"
159
+
160
+ #: ../includes/class-wcpdf-settings.php:215
161
+ msgid "Customer Completed Order email"
162
+ msgstr "e-mail obavijest klijentu o dovršenoj narudžbi"
163
+
164
+ #: ../includes/class-wcpdf-settings.php:216
165
+ msgid "Customer Invoice email"
166
+ msgstr "E-mail klijenta za dostavu računa"
167
+
168
+ #: ../includes/class-wcpdf-settings.php:225
169
+ msgid "Attach invoice to:"
170
+ msgstr "Privitak računa za:"
171
+
172
+ #: ../includes/class-wcpdf-settings.php:233
173
+ #, php-format
174
+ msgid ""
175
+ "It looks like the temp folder (<code>%s</code>) is not writable, check the "
176
+ "permissions for this folder! Without having write access to this folder, the "
177
+ "plugin will not be able to email invoices."
178
+ msgstr ""
179
+ "Čini se kako je temp folder (<code>%s</code>) zaštićen od pisanja, "
180
+ "provjerite dozvole za ovaj folder. Bez ovlasti za upisivanje u ovaj folder "
181
+ "plugin neće biti u mogućnosti poslati račune e-mailom."
182
+
183
+ #: ../includes/class-wcpdf-settings.php:239
184
+ msgid "Disable for free products"
185
+ msgstr "Onemogući za besplatne proizvode"
186
+
187
+ #: ../includes/class-wcpdf-settings.php:246
188
+ msgid ""
189
+ "Disable automatic creation/attachment of invoices when only free products "
190
+ "are ordered"
191
+ msgstr ""
192
+ "Onemogući automatiziranu izradu/dodavanje računa kada su naručeni isključivo "
193
+ "besplatni proizvodi/usluge"
194
+
195
+ #: ../includes/class-wcpdf-settings.php:253
196
+ msgid "Interface"
197
+ msgstr "Sučelje"
198
+
199
+ #: ../includes/class-wcpdf-settings.php:301
200
+ msgid "Allow My Account invoice download"
201
+ msgstr "Dozvoliti preuzimanje računa za moj korisnički profil"
202
+
203
+ #: ../includes/class-wcpdf-settings.php:309
204
+ msgid "Only when an invoice is already created/emailed"
205
+ msgstr "Samo kada je račun već izrađen/poslan"
206
+
207
+ #: ../includes/class-wcpdf-settings.php:310
208
+ msgid "Only for specific order statuses (define below)"
209
+ msgstr "Samo za specifične statuse narudžbe (definirati ispod)"
210
+
211
+ #: ../includes/class-wcpdf-settings.php:311
212
+ msgid "Always"
213
+ msgstr "Uvijek"
214
+
215
+ #: ../includes/class-wcpdf-settings.php:312
216
+ msgid "Never"
217
+ msgstr "Nikad"
218
+
219
+ #: ../includes/class-wcpdf-settings.php:327
220
+ msgid "Enable invoice number column in the orders list"
221
+ msgstr "Omogućite prikaz stupca s brojem računa u listi narudžbi"
222
+
223
+ #: ../includes/class-wcpdf-settings.php:365
224
+ msgid "PDF Template settings"
225
+ msgstr "PDF predložak : postavke"
226
+
227
+ #: ../includes/class-wcpdf-settings.php:377
228
+ msgid "Choose a template"
229
+ msgstr "Odaberite predložak"
230
+
231
+ #: ../includes/class-wcpdf-settings.php:385
232
+ #, php-format
233
+ msgid ""
234
+ "Want to use your own template? Copy all the files from <code>%s</code> to "
235
+ "your (child) theme in <code>%s</code> to customize them"
236
+ msgstr ""
237
+ "Želite koristiti vlastiti predložak? Kopirajte sve datoteke iz "
238
+ "<code>%s</code> u vašu \"child\" temu u <code>%s</code> kako bi ih mogli "
239
+ "prilagođavati"
240
+
241
+ #: ../includes/class-wcpdf-settings.php:391
242
+ msgid "Paper size"
243
+ msgstr "Veličina papira"
244
+
245
+ #: ../includes/class-wcpdf-settings.php:399
246
+ msgid "A4"
247
+ msgstr "A4"
248
+
249
+ #: ../includes/class-wcpdf-settings.php:400
250
+ msgid "Letter"
251
+ msgstr "Pismo"
252
+
253
+ #: ../includes/class-wcpdf-settings.php:407
254
+ msgid "Shop header/logo"
255
+ msgstr "Zaglavlje/Logo trgovine"
256
+
257
+ #: ../includes/class-wcpdf-settings.php:414
258
+ msgid "Select or upload your invoice header/logo"
259
+ msgstr "Odaberite ili prenesite datoteku zaglavlja/logo-a za račun"
260
+
261
+ #: ../includes/class-wcpdf-settings.php:415
262
+ msgid "Set image"
263
+ msgstr "Odabir slike"
264
+
265
+ #: ../includes/class-wcpdf-settings.php:416
266
+ msgid "Remove image"
267
+ msgstr "Ukloni sliku"
268
+
269
+ #: ../includes/class-wcpdf-settings.php:423
270
+ msgid "Shop Name"
271
+ msgstr "Ime trgovine"
272
+
273
+ #: ../includes/class-wcpdf-settings.php:437
274
+ msgid "Shop Address"
275
+ msgstr "Adresa trgovine"
276
+
277
+ #: ../includes/class-wcpdf-settings.php:453
278
+ msgid "Footer: terms & conditions, policies, etc."
279
+ msgstr "Podnožje: uvjeti & statusne stvari, poslovanje i sl."
280
+
281
+ #: ../includes/class-wcpdf-settings.php:477
282
+ msgid "Display shipping address"
283
+ msgstr "Prikazati adresu dostave"
284
+
285
+ #: ../includes/class-wcpdf-settings.php:484
286
+ msgid ""
287
+ "Display shipping address on invoice (in addition to the default billing "
288
+ "address) if different from billing address"
289
+ msgstr ""
290
+ "Prikazati adresu dostave na računu (kao dodatak predodređene adrese za "
291
+ "naplatu) ako je različita od adrese za naplatu"
292
+
293
+ #: ../includes/class-wcpdf-settings.php:490 ../includes/class-wcpdf-settings.php:
294
+ #: 637
295
+ msgid "Display email address"
296
+ msgstr "Prikaži e-mail adresu"
297
+
298
+ #: ../includes/class-wcpdf-settings.php:502 ../includes/class-wcpdf-settings.php:
299
+ #: 649
300
+ msgid "Display phone number"
301
+ msgstr "Prikaži broj telefona"
302
+
303
+ #: ../includes/class-wcpdf-settings.php:514
304
+ msgid "Display invoice date"
305
+ msgstr "Prikaži datum izrade računa"
306
+
307
+ #: ../includes/class-wcpdf-settings.php:527
308
+ msgid "Display built-in sequential invoice number"
309
+ msgstr "Prikaži ugrađenu sekvencu broja računa"
310
+
311
+ #: ../includes/class-wcpdf-settings.php:542
312
+ msgid "Next invoice number (without prefix/suffix etc.)"
313
+ msgstr "Slijedeći broj računa (bez prefiksa i sufiksa)"
314
+
315
+ #: ../includes/class-wcpdf-settings.php:550
316
+ msgid ""
317
+ "This is the number that will be used on the next invoice that is created. By "
318
+ "default, numbering starts from the WooCommerce Order Number of the first "
319
+ "invoice that is created and increases for every new invoice. Note that if "
320
+ "you override this and set it lower than the highest (PDF) invoice number, "
321
+ "this could create double invoice numbers!"
322
+ msgstr ""
323
+ "Ovo je broj koji će se koristiti na prvom slijedećem generiranom računu. "
324
+ "Prema pretpostavljenim postavkama, brojanje započinje od Woocommerce broja "
325
+ "narudžbe i prvog generiranog računa i broj se uvećava za svaki novi račun. "
326
+ "Obratite pozornost na to ako ovo premostite i postavite na nižu vrijednost "
327
+ "od najvišeg (PDF) broja računa, moglo bi se dogoditi da imate kreirane "
328
+ "dvostruke brojeve računa."
329
+
330
+ #: ../includes/class-wcpdf-settings.php:574
331
+ msgid "Invoice number format"
332
+ msgstr "Format broja računa"
333
+
334
+ #: ../includes/class-wcpdf-settings.php:583
335
+ msgid "Prefix"
336
+ msgstr "Prefiks"
337
+
338
+ #: ../includes/class-wcpdf-settings.php:585
339
+ msgid ""
340
+ "to use the invoice year and/or month, use [invoice_year] or [invoice_month] "
341
+ "respectively"
342
+ msgstr ""
343
+ "kako bi koristili godinu i/ili mjesec, koristite [invoice_year] ili "
344
+ "[invoice_month] poštujući"
345
+
346
+ #: ../includes/class-wcpdf-settings.php:588
347
+ msgid "Suffix"
348
+ msgstr "Sufiks"
349
+
350
+ #: ../includes/class-wcpdf-settings.php:593
351
+ msgid "Padding"
352
+ msgstr "prostor "
353
+
354
+ #: ../includes/class-wcpdf-settings.php:595
355
+ msgid "enter the number of digits here - enter \"6\" to display 42 as 000042"
356
+ msgstr ""
357
+ "unesite broj znamenki ovdje - unesite\"6\" ako želite prikazati broj 42 kao "
358
+ "000042"
359
+
360
+ #: ../includes/class-wcpdf-settings.php:598
361
+ msgid ""
362
+ "note: if you have already created a custom invoice number format with a "
363
+ "filter, the above settings will be ignored"
364
+ msgstr ""
365
+ "Bilješka: Ako ste već kreirali prilagođeni format broja računa s filterom, "
366
+ "gornje postavke biti će zanemarene"
367
+
368
+ #: ../includes/class-wcpdf-settings.php:604
369
+ msgid "Reset invoice number yearly"
370
+ msgstr "Resetirati broj računa na godišnjoj razini"
371
+
372
+ #: ../includes/class-wcpdf-settings.php:624
373
+ msgid "Display billing address"
374
+ msgstr "Prikazati adresu za naplatu"
375
+
376
+ #: ../includes/class-wcpdf-settings.php:631
377
+ msgid ""
378
+ "Display billing address on packing slip (in addition to the default shipping "
379
+ "address) if different from shipping address"
380
+ msgstr ""
381
+ "Prikazati adresu za naplatu na paketnom slipu (kao dodatak pretpostavljenoj "
382
+ "adresi za dostavu) ako se ralikuje od adrese za dostavu"
383
+
384
+ #: ../includes/class-wcpdf-settings.php:662
385
+ msgid "Extra template fields"
386
+ msgstr "Dodatna polja predloška"
387
+
388
+ #: ../includes/class-wcpdf-settings.php:669
389
+ msgid "Extra field 1"
390
+ msgstr "Dodatno polje 1"
391
+
392
+ #: ../includes/class-wcpdf-settings.php:678
393
+ msgid "This is footer column 1 in the <i>Modern (Premium)</i> template"
394
+ msgstr "Ovo je 1 kolona footera (podnožja) u <i>Modern (Premium)</i> predlošku"
395
+
396
+ #: ../includes/class-wcpdf-settings.php:685
397
+ msgid "Extra field 2"
398
+ msgstr "Dodatno polje 2"
399
+
400
+ #: ../includes/class-wcpdf-settings.php:694
401
+ msgid "This is footer column 2 in the <i>Modern (Premium)</i> template"
402
+ msgstr "Ovo je 2 kolona footera (podnožja) u <i>Modern (Premium)</i> predlošku"
403
+
404
+ #: ../includes/class-wcpdf-settings.php:701
405
+ msgid "Extra field 3"
406
+ msgstr "Dodatno polje 3"
407
+
408
+ #: ../includes/class-wcpdf-settings.php:710
409
+ msgid "This is footer column 3 in the <i>Modern (Premium)</i> template"
410
+ msgstr "Ovo je 3 kolona footera (podnožja) u <i>Modern (Premium)</i> predlošku"
411
+
412
+ #: ../includes/class-wcpdf-settings.php:732
413
+ msgid "Debug settings"
414
+ msgstr "Postavke debug-a"
415
+
416
+ #: ../includes/class-wcpdf-settings.php:739
417
+ msgid "Enable debug output"
418
+ msgstr "Omogućiti debug prikaz"
419
+
420
+ #: ../includes/class-wcpdf-settings.php:746
421
+ msgid ""
422
+ "Enable this option to output plugin errors if you're getting a blank page or "
423
+ "other PDF generation issues"
424
+ msgstr ""
425
+ "Omogući ovu opciju kako bi dohvatili greške priključka ako vam se događa da "
426
+ "dobivate praznu stranicu nakon generiranja PDF-a ili imate neke druge "
427
+ "poteškoće"
428
+
429
+ #: ../includes/class-wcpdf-settings.php:752
430
+ msgid "Output to HTML"
431
+ msgstr "Prikaži u HTML-u"
432
+
433
+ #: ../includes/class-wcpdf-settings.php:759
434
+ msgid "Send the template output as HTML to the browser instead of creating a PDF."
435
+ msgstr "Pošalji predložak u HTML formatu umjesto generiranja PDF-a."
436
+
437
+ #: ../includes/class-wcpdf-settings.php:765
438
+ msgid "Use old tmp folder"
439
+ msgstr "Koristiti stari tmp folder"
440
+
441
+ #: ../includes/class-wcpdf-settings.php:772
442
+ msgid ""
443
+ "Before version 1.5 of PDF Invoices, temporary files were stored in the "
444
+ "plugin folder. This setting is only intended for backwards compatibility, "
445
+ "not recommended on new installs!"
446
+ msgstr ""
447
+ "Prije verzije 1.5 ili PDF računa, privremene datoteke su se pohranjivale u "
448
+ "plugin folder. Ove postavke su namijenjene samo za pozadinsku kompatibilnost,"
449
+ " nisu namijenjene novim instalacijama!"
450
+
451
+ #: ../includes/class-wcpdf-settings.php:1187
452
+ msgid "Image resolution"
453
+ msgstr "Rezolucija slike"
454
+
455
+ #: ../includes/class-wcpdf-settings.php:1303
456
+ msgid ""
457
+ "<b>Warning!</b> The settings below are meant for debugging/development only. "
458
+ "Do not use them on a live website!"
459
+ msgstr ""
460
+ "Upozorenje! Donje postavke su namijenjene isključivo za "
461
+ "debugging/development. Ne koristite ih na stranicama koje su puštene u "
462
+ "produkciju."
463
+
464
+ #: ../includes/class-wcpdf-settings.php:1312
465
+ msgid ""
466
+ "These are used for the (optional) footer columns in the <em>Modern "
467
+ "(Premium)</em> template, but can also be used for other elements in your "
468
+ "custom template"
469
+ msgstr ""
470
+ "Ovo se koristi za (opcionalno) retke u podnožju (footeru) <em>Modern "
471
+ "(Premium)</em> predlošku, ali se također može koristiti za druge elemente u "
472
+ "vašem prilagođenom predlošku"
473
+
474
+ #: ../includes/wcpdf-extensions.php:15
475
+ msgid "Check out these premium extensions!"
476
+ msgstr "Provjerite ove premium dodatke!"
477
+
478
+ #: ../includes/wcpdf-extensions.php:16
479
+ msgid "click items to read more"
480
+ msgstr "klik na predmet za detalje"
481
+
482
+ #: ../includes/wcpdf-extensions.php:23
483
+ msgid "Go Pro: Proforma invoices, credit notes (=refunds) & more!"
484
+ msgstr "Idemo na PRO: Proforma računi, kreditne bilješke (=povrat sredstava) i više!"
485
+
486
+ #: ../includes/wcpdf-extensions.php:25
487
+ msgid ""
488
+ "Supercharge WooCommerce PDF Invoices & Packing Slips with the following "
489
+ "features:"
490
+ msgstr ""
491
+ "SuperCharge-ajte WooCommerce PDF Računi i Paketni Slipovi dodatak sa "
492
+ "slijedećim mogućnostima:"
493
+
494
+ #: ../includes/wcpdf-extensions.php:27
495
+ msgid "Email/print/download <b>PDF Credit Notes & Proforma invoices</b>"
496
+ msgstr "E-mail/Ispis/Preuzimanje <b>PDF Kreditne bilješke & Proforma Računa</b>"
497
+
498
+ #: ../includes/wcpdf-extensions.php:28
499
+ msgid ""
500
+ "Send out a separate <b>notification email</b> with (or without) PDF "
501
+ "invoices/packing slips, for example to a drop-shipper or a supplier."
502
+ msgstr ""
503
+ "Pošalji odvojeni <b>E-mail obavijest</b> sa (ili bez) PDF računa/paketnih "
504
+ "slipova, za primjer dostavljaču ili "
505
+
506
+ #: ../includes/wcpdf-extensions.php:29
507
+ msgid ""
508
+ "Attach <b>up to 3 static files</b> (for example a terms & conditions "
509
+ "document) to the WooCommerce emails of your choice."
510
+ msgstr ""
511
+ "Dodajte <b> do 3 statične datoteke</b> (Npr. dokument Uvjeti poslovanja) u "
512
+ "WooCommerce e-mail poruke po vašem izboru"
513
+
514
+ #: ../includes/wcpdf-extensions.php:30
515
+ msgid ""
516
+ "Use <b>separate numbering systems</b> and/or format for proforma invoices "
517
+ "and credit notes or utilize the main invoice numbering system"
518
+ msgstr ""
519
+ "Korištenje <b>odvojenih sustava knjiženja</b> i/ili formata za proforma "
520
+ "račune i kreditne bilješke ili primjena glavnog računskog sustava knjiženja"
521
+
522
+ #: ../includes/wcpdf-extensions.php:31
523
+ msgid ""
524
+ "<b>Customize</b> the <b>shipping & billing address</b> format to include "
525
+ "additional custom fields, font sizes etc. without the need to create a "
526
+ "custom template."
527
+ msgstr ""
528
+ "<b>Uredite</b> format <b>adrese za dostavu i naplatu</b> kako bi dodali "
529
+ "dodatna prilagođena polja, veličine fonta i sl. bez potrebe za izradom novog "
530
+ "predloška. "
531
+
532
+ #: ../includes/wcpdf-extensions.php:32
533
+ msgid "Use the plugin in multilingual <b>WPML</b> setups"
534
+ msgstr "Koristite dodatak u višejezičnom <b>WPML</b> postavkama"
535
+
536
+ #: ../includes/wcpdf-extensions.php:34
537
+ msgid "Get WooCommerce PDF Invoices & Packing Slips Professional!"
538
+ msgstr "Pribavite WooCmmerce Računi & Paketni slipovi Profesionalnu verziju!"
539
+
540
+ #: ../includes/wcpdf-extensions.php:42
541
+ msgid "Upload all invoices automatically to your dropbox"
542
+ msgstr "Prijenos svih računa automatski na Dropbox"
543
+
544
+ #: ../includes/wcpdf-extensions.php:48
545
+ msgid ""
546
+ "This extension conveniently uploads all the invoices (and other pdf "
547
+ "documents from the professional extension) that are emailed to your "
548
+ "customers to Dropbox. The best way to keep your invoice administration up to "
549
+ "date!"
550
+ msgstr ""
551
+ "Ovo proširenje pouzdano prenosi sve račune ( i druge PDF dokumente s "
552
+ "profesionalnog proširenja) koja su poslana e-mailom vašim klijentima, "
553
+ "izravno na Dropbox. Najbolji način za održavanje vaše administracije računa "
554
+ "preglednim i ažurnim."
555
+
556
+ #: ../includes/wcpdf-extensions.php:49
557
+ msgid "Get WooCommerce PDF Invoices & Packing Slips to dropbox!"
558
+ msgstr "Povucite WooCOmmerce Račune i paketne slipove u dropbox!"
559
+
560
+ #: ../includes/wcpdf-extensions.php:61
561
+ msgid ""
562
+ "Automatically send new orders or packing slips to your printer, as soon as "
563
+ "the customer orders!"
564
+ msgstr ""
565
+ "AUtomatski pošalji nove narudžbe ili pakente slipove na vaš printer, u "
566
+ "trenutku kada klijent izvši narudžbu!"
567
+
568
+ #: ../includes/wcpdf-extensions.php:67
569
+ msgid ""
570
+ "Check out the WooCommerce Automatic Order Printing extension from our "
571
+ "partners at Simba Hosting"
572
+ msgstr ""
573
+ "Provjerite WooCommerce dodatak ispis Automatske Narudžbe izrađen od strane "
574
+ "naših partnera @ Simba Hosting"
575
+
576
+ #: ../includes/wcpdf-extensions.php:68
577
+ msgid "WooCommerce Automatic Order Printing"
578
+ msgstr "WooCOmmerce Ispis Automatske narudžbe"
579
+
580
+ #: ../includes/wcpdf-extensions.php:82
581
+ msgid "Advanced, customizable templates"
582
+ msgstr "Napredni, prilagodljivi predlošci"
583
+
584
+ #: ../includes/wcpdf-extensions.php:85
585
+ msgid ""
586
+ "Completely customize the invoice contents (prices, taxes, thumbnails) to "
587
+ "your needs with a drag & drop customizer"
588
+ msgstr ""
589
+ "Potpuna prilagodba sadržaja računa (cijene, porezi, umanjene slike) vašim "
590
+ "potrebamakorištenjem povuci & ispusti uređivača"
591
+
592
+ #: ../includes/wcpdf-extensions.php:86
593
+ msgid "Two extra stylish premade templates (Modern & Business)"
594
+ msgstr "Dva vrlo stilizirana pripremljena predloška (Moderni & Poslovni)"
595
+
596
+ #: ../includes/wcpdf-extensions.php:87
597
+ #, php-format
598
+ msgid "Check out the Premium PDF Invoice & Packing Slips templates at %s."
599
+ msgstr "Provjerite Premium PDF Računi & Slipovi paketa predloške na %s."
600
+
601
+ #: ../includes/wcpdf-extensions.php:88
602
+ #, php-format
603
+ msgid "For custom templates, contact us at %s."
604
+ msgstr "Za prilagođene teme, kontaktirajte nas na %s."
605
+
606
+ #: ../includes/class-wcpdf-writepanels.php:33
607
+ msgid "PDF Packing Slips"
608
+ msgstr "PDF Paketni slipovi"
609
+
610
+ #: ../includes/class-wcpdf-writepanels.php:120 ../includes/class-wcpdf-
611
+ #: writepanels.php:252 ../includes/class-wcpdf-writepanels.php:253
612
+ msgid "PDF Invoice"
613
+ msgstr "PDF račun"
614
+
615
+ #: ../includes/class-wcpdf-writepanels.php:125 ../includes/class-wcpdf-
616
+ #: writepanels.php:257 ../includes/class-wcpdf-writepanels.php:258
617
+ msgid "PDF Packing Slip"
618
+ msgstr "PDF paketni slip"
619
+
620
+ #: ../includes/class-wcpdf-writepanels.php:152
621
+ msgid "Invoice Number"
622
+ msgstr "Broj računa"
623
+
624
+ #: ../includes/class-wcpdf-writepanels.php:211
625
+ msgid "Download invoice (PDF)"
626
+ msgstr "Dohvati račun(PDF)"
627
+
628
+ #: ../includes/class-wcpdf-writepanels.php:225
629
+ msgid "Create PDF"
630
+ msgstr "Generiraj PDF"
631
+
632
+ #: ../includes/class-wcpdf-writepanels.php:235
633
+ msgid "PDF Invoice data"
634
+ msgstr "Sadržaj PDF računa"
635
+
636
+ #: ../includes/class-wcpdf-writepanels.php:288
637
+ msgid "Invoice Number (unformatted!)"
638
+ msgstr "Broj računa (neformatiran!)"
639
+
640
+ #: ../includes/class-wcpdf-writepanels.php:296 ../templates/pdf/Simple/invoice.
641
+ #: php:55
642
+ msgid "Invoice Date:"
643
+ msgstr "Datum računa:"
644
+
645
+ #: ../includes/class-wcpdf-writepanels.php:298
646
+ msgid "h"
647
+ msgstr "s"
648
+
649
+ #: ../includes/class-wcpdf-writepanels.php:298
650
+ msgid "m"
651
+ msgstr "m"
652
+
653
+ #: ../includes/class-wcpdf-export.php:407 ../includes/class-wcpdf-export.php:421 .
654
+ #: ./includes/class-wcpdf-export.php:428 ../includes/class-wcpdf-export.php:436
655
+ msgid "You do not have sufficient permissions to access this page."
656
+ msgstr "Nemate dovoljne ovlasti kako bi pristupili ovoj stranici."
657
+
658
+ #: ../includes/class-wcpdf-export.php:412
659
+ msgid "Some of the export parameters are missing."
660
+ msgstr "Neki od parametara za izvoz nedostaju."
661
+
662
+ #: ../includes/class-wcpdf-export.php:493
663
+ msgid "invoice"
664
+ msgid_plural "invoices"
665
+ msgstr[0] "Račun"
666
+ msgstr[1] "Računi"
667
+
668
+ #: ../includes/class-wcpdf-export.php:497
669
+ msgid "packing-slip"
670
+ msgid_plural "packing-slips"
671
+ msgstr[0] "Slip uz paket"
672
+ msgstr[1] "Slipovi za pakete"
673
+
674
+ #: ../templates/pdf/Simple/packing-slip.php:29
675
+ msgid "Shipping Address:"
676
+ msgstr "Adresa za dostavu:"
677
+
678
+ #: ../templates/pdf/Simple/packing-slip.php:40 ../templates/pdf/Simple/invoice.
679
+ #: php:29
680
+ msgid "Billing Address:"
681
+ msgstr "Adresa za naplatu:"
682
+
683
+ #: ../templates/pdf/Simple/packing-slip.php:48 ../templates/pdf/Simple/invoice.
684
+ #: php:60
685
+ msgid "Order Number:"
686
+ msgstr "Broj narudžbe"
687
+
688
+ #: ../templates/pdf/Simple/packing-slip.php:52 ../templates/pdf/Simple/invoice.
689
+ #: php:64
690
+ msgid "Order Date:"
691
+ msgstr "Datum narudžbe:"
692
+
693
+ #: ../templates/pdf/Simple/packing-slip.php:56
694
+ msgid "Shipping Method:"
695
+ msgstr "Metoda dostave:"
696
+
697
+ #: ../templates/pdf/Simple/packing-slip.php:70 ../templates/pdf/Simple/invoice.
698
+ #: php:82
699
+ msgid "Product"
700
+ msgstr "Proizvod"
701
+
702
+ #: ../templates/pdf/Simple/packing-slip.php:71 ../templates/pdf/Simple/invoice.
703
+ #: php:83
704
+ msgid "Quantity"
705
+ msgstr "Količina"
706
+
707
+ #: ../templates/pdf/Simple/packing-slip.php:78 ../templates/pdf/Simple/invoice.
708
+ #: php:91
709
+ msgid "Description"
710
+ msgstr "Opis"
711
+
712
+ #: ../templates/pdf/Simple/packing-slip.php:83 ../templates/pdf/Simple/invoice.
713
+ #: php:96
714
+ msgid "SKU"
715
+ msgstr "Broj artikla:"
716
+
717
+ #: ../templates/pdf/Simple/packing-slip.php:84 ../templates/pdf/Simple/invoice.
718
+ #: php:97
719
+ msgid "SKU:"
720
+ msgstr "Broj Artikla:"
721
+
722
+ #: ../templates/pdf/Simple/packing-slip.php:85 ../templates/pdf/Simple/invoice.
723
+ #: php:98
724
+ msgid "Weight:"
725
+ msgstr "Težina"
726
+
727
+ #: ../templates/pdf/Simple/packing-slip.php:99 ../templates/pdf/Simple/invoice.
728
+ #: php:112
729
+ msgid "Customer Notes"
730
+ msgstr "Bilješke klijenta"
731
+
732
+ #: ../templates/pdf/Simple/invoice.php:40
733
+ msgid "Ship To:"
734
+ msgstr "Dostava na:"
735
+
736
+ #: ../templates/pdf/Simple/invoice.php:49
737
+ msgid "Invoice Number:"
738
+ msgstr "Broj računa:"
739
+
740
+ #: ../templates/pdf/Simple/invoice.php:68
741
+ msgid "Payment Method:"
742
+ msgstr "Metoda Plaćanja:"
743
+
744
+ #: ../templates/pdf/Simple/invoice.php:84
745
+ msgid "Price"
746
+ msgstr "CIjena"
747
+
readme.txt CHANGED
@@ -1,597 +1,602 @@
1
- === Plugin Name ===
2
- Contributors: pomegranate
3
- Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
4
- Requires at least: 3.5
5
- Tested up to: 4.4.1
6
- Stable tag: 1.5.28
7
- License: GPLv2 or later
8
- License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
-
10
- Create, print & automatically email PDF invoices & packing slips for WooCommerce orders.
11
-
12
- == Description ==
13
-
14
- This WooCommerce extension automatically adds a PDF invoice to the order confirmation emails sent out to your customers. Includes a basic template (additional templates are available from [WP Overnight](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)) as well as the possibility to modify/create your own templates. In addition, you can choose to download or print invoices and packing slips from the WooCommerce order admin.
15
-
16
- = Main features =
17
- * Automatically attach invoice PDF to WooCommerce emails of your choice
18
- * Download the PDF invoice / packing slip from the order admin page
19
- * Generate PDF invoices / packings slips in bulk
20
- * **Fully customizable** HTML/CSS invoice templates
21
- * Download invoices from the My Account page
22
- * Sequential invoice numbers - with custom formatting
23
- * **Available in: Czech, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese (see FAQ for adding custom fonts!), Norwegian, Polish, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish & Ukrainian**
24
-
25
- In addition to this, we offer several premium extensions:
26
-
27
- * Create/email PDF Proforma Invoices, Credit Notes (for Refunds), email Packing Slips & more with [WooCommerce PDF Invoices & Packing Slips Professional](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
28
- * Upload all invoices automatically to Dropbox with [WooCommerce PDF Invoices & Packing Slips to Dropbox](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-dropbox/)
29
- * Automatically send new orders or packing slips to your printer, as soon as the customer orders! [WooCommerce Automatic Order Printing](https://www.simbahosting.co.uk/s3/product/woocommerce-automatic-order-printing/?affiliates=2) (from our partners at Simba Hosting)
30
- * More advanced & stylish templates with [WooCommerce PDF Invoices & Packing Slips Premium Templates](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)
31
-
32
- = Fully customizable =
33
- In addition to a number of default settings (including a custom header/logo) and several layout fields that you can use out of the box, the plugin contains HTML/CSS based templates that allow for customization & full control over the PDF output. Copy the templates to your theme folder and you don't have to worry that your customizations will be overwritten when you update the plugin.
34
-
35
- * Insert customer header image/logo
36
- * Modify shop data / footer / disclaimer etc. on the invoices & packing slips
37
- * Select paper size (Letter or A4)
38
- * Translation ready
39
-
40
- == Installation ==
41
-
42
- = Minimum Requirements =
43
-
44
- * WooCommerce 2.0 or later
45
- * WordPress 3.5 or later
46
-
47
- = Automatic installation =
48
- Automatic installation is the easiest option as WordPress handles the file transfers itself and you don't even need to leave your web browser. To do an automatic install of WooCommerce PDF Invoices & Packing Slips, log in to your WordPress admin panel, navigate to the Plugins menu and click Add New.
49
-
50
- In the search field type "WooCommerce PDF Invoices & Packing Slips" and click Search Plugins. You can install it by simply clicking Install Now. After clicking that link you will be asked if you're sure you want to install the plugin. Click yes and WordPress will automatically complete the installation. After installation has finished, click the 'activate plugin' link.
51
-
52
- = Manual installation via the WordPress interface =
53
- 1. Download the plugin zip file to your computer
54
- 2. Go to the WordPress admin panel menu Plugins > Add New
55
- 3. Choose upload
56
- 4. Upload the plugin zip file, the plugin will now be installed
57
- 5. After installation has finished, click the 'activate plugin' link
58
-
59
- = Manual installation via FTP =
60
- 1. Download the plugin file to your computer and unzip it
61
- 2. Using an FTP program, or your hosting control panel, upload the unzipped plugin folder to your WordPress installation's wp-content/plugins/ directory.
62
- 3. Activate the plugin from the Plugins menu within the WordPress admin.
63
-
64
- == Frequently Asked Questions ==
65
-
66
- Make sure to check out [WooCommerce PDF Invoices & Packing Slips documentation](http://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/) on our site - it covers most of the questions below (and more!) in more detail!
67
-
68
- = How do I create my own custom template? =
69
-
70
- Copy the files from `wp-content/plugins/woocommerce-pdf-invoices-packing-slips/templates/pdf/Simple/` to your (child) theme in `wp-content/themes/yourtheme/woocommerce/pdf/yourtemplate` and customize them there. The new template will show up as 'yourtemplate' (the folder name) in the settings panel.
71
-
72
- = Where can I find more templates? =
73
-
74
- Go to [wpovernight.com](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/) to checkout more templates! These include templates with more tax details and product thumbnails. Need a custom templates? Contact us at support@wpovernight.com for more information.
75
-
76
- = Can I create/send a proforma invoice or a credit note? =
77
- This is a feature of our Professional extension, which can be found at [wpovernight.com](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
78
-
79
- = Can I contribute to the code? =
80
- You're more than welcome! This plugin is hosted on github, where you can post issues or make pull requests.
81
- https://github.com/wpovernight/woocommerce-pdf-invoices-packing-slips
82
-
83
- = My language is not included, how can I contribute? =
84
-
85
- This plugin is translation ready, which means that you can translate it using standard WordPress methods.
86
-
87
- 1. Download POEdit at (http://www.poedit.net/download.php)
88
- 2. Open POEdit
89
- 3. File > New from POT
90
- 4. Open wpo_wcpdf.pot (from `woocommerce-pdf-invoices-packing-slips/languages/`)
91
- 5. A popup will ask you for your language
92
- 6. This step is a bit tricky, configuring the plurals. Somehow the settings can't be copied from the pot. Go to Catalogue > Preferences. Then enter nplurals=2; plural=n != 1; in the custom expression field
93
- 7. Enter the translations. invoice and packing-slip now have two translation fields, single & plural. Note that this is a filename, so replace spaces with a - just to be sure!
94
- 8. Save as `wpo_wcpdf-xx_XX.po`, where you replace xx_XX with your language code & country code suffix (da_DK, pl_PL, de_DE etc.)
95
-
96
- = How can I use my own font? =
97
- Although the plugin supports webfonts, this is somewhat limited and has a lot of caveats, read [this thread](https://wordpress.org/support/topic/webfonts-within-a-custom-template-not-rendering-in-pdf?replies=4#post-5395442) on the forum.
98
- Some languages (Japanese, Chinese, etc.) are not supported by the default font included with the plugin, in this case a custom font is required.
99
- The best method is to create a custom template first (see above), then add a `fonts/` folder to that template and use the following code (replace the font names/filenames) to load the font in the style.css from the pdf template:
100
- `
101
- <?php global $wpo_wcpdf;?>
102
- /* Load font */
103
- @font-face {
104
- font-family: 'MyFont';
105
- font-style: normal;
106
- font-weight: normal;
107
- src: local('MyFont'), local('MyFont'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont.ttf) format('truetype');
108
- }
109
- @font-face {
110
- font-family: 'MyFont';
111
- font-style: normal;
112
- font-weight: bold;
113
- src: local('MyFont Bold'), local('MyFont-Bold'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-bold.ttf) format('truetype');
114
- }
115
- @font-face {
116
- font-family: 'MyFont';
117
- font-style: italic;
118
- font-weight: normal;
119
- src: local('MyFont Italic'), local('MyFont-Italic'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-italic.ttf) format('truetype');
120
- }
121
- @font-face {
122
- font-family: 'MyFont';
123
- font-style: italic;
124
- font-weight: bold;
125
- src: local('MyFont Bold Italic'), local('MyFont-BoldItalic'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-bolditalic.ttf) format('truetype');
126
- }
127
- `
128
- then make sure you assign that font family to the body or other elements of the template:
129
- `
130
- font-family: 'MyFont';
131
- `
132
-
133
- Some notes:
134
-
135
- * Only TTF fonts are supported.
136
- * You can't use numeric font weights (like 700 instead of bold)!
137
- * Avoid spaces or special characters in the font filenames.
138
- * I have found that not all servers cope well with the font paths. If this is the case with your font, try to put the font in the root of your site and put that in the font url (i.e. `url(http://yoursite.com/fonts/myfont-italic.ttf)` )
139
-
140
- Some font links:
141
-
142
- * Japanese - http://ipafont.ipa.go.jp/index.html
143
- * Chinese - http://www.study-area.org/apt/firefly-font/
144
-
145
- = How can I display the HTML/CSS source for debugging/developing templates? =
146
- There's a setting on the Status tab of the settings page that allows you to toggle HTML output. Don't forget to turn if off after you're done testing!
147
-
148
- = How can I display custom fields in the invoice or packing slip? =
149
- First, you need to create a custom template following instructions from the first item in this FAQ.
150
- Then place the following snippet where you would like the custom field to appear:
151
-
152
- `
153
- <?php $wpo_wcpdf->custom_field('custom_fieldname', 'Custom field:'); ?>
154
- `
155
-
156
- Where you replace 'custom_fieldname' with the name of the field you want to display, and 'Custom field' with the label. The plugin only displays the field when it contains data. If you also want to display the label when the field is empty, you can pass a third parameter (true), like this:
157
-
158
- `
159
- <?php $wpo_wcpdf->custom_field('custom_fieldname', 'Custom field:', true); ?>
160
- `
161
-
162
- = How can I display order notes in the invoice or packing slip? =
163
- First, you need to create a custom template following instructions from the first item in this FAQ.
164
- Then place the following snippet where you would like the order notes to appear:
165
-
166
- `
167
- <?php $wpo_wcpdf->order_notes(); ?>
168
- `
169
-
170
- if you want to display all order notes, including the (private) admin notes, use:
171
- `
172
- <?php $wpo_wcpdf->order_notes('all'); ?>
173
- `
174
-
175
- = How do can I modify the pdf filename? =
176
- You can do this via a filter in your theme's `functions.php` (Some themes have a "custom functions" area in the settings).
177
-
178
- Here's a simple example for putting your shop name in front of the filname.
179
- `
180
- add_filter( 'wpo_wcpdf_filename', 'wpo_wcpdf_custom_filename', 10, 4 );
181
- function wpo_wcpdf_custom_filename( $filename, $template_type, $order_ids, $context ) {
182
- // prepend your shopname to the file
183
- $new_filename = 'myshopname_' . $filename;
184
-
185
- return $new_filename;
186
- }
187
- `
188
- You can also use the $template_type ('invoice' or 'packing-slip'), $order_ids (single array) or $context ('download' or 'attachment') variables to make more complex rules for the filename.
189
-
190
- = How can I add a download link to the invoice on the Thank you page? =
191
- You can do this with an action in your theme's `functions.php` (Some themes have a "custom functions" area in the settings). Note that due to security restrictions, this will only work for registered/logged in users!
192
-
193
- `
194
- add_filter('woocommerce_thankyou_order_received_text', 'wpo_wcpdf_thank_you_link', 10, 2);
195
- function wpo_wcpdf_thank_you_link( $text, $order ) {
196
- if ( is_user_logged_in() ) {
197
- $pdf_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=generate_wpo_wcpdf&template_type=invoice&order_ids=' . $order->id . '&my-account'), 'generate_wpo_wcpdf' );
198
- $text .= '<p><a href="'.esc_attr($pdf_url).'">Download a printable invoice / payment confirmation (PDF format)</a></p>';
199
- }
200
- return $text;
201
- }
202
- `
203
-
204
- alternatively, you can hook this text to the `woocommerce_thankyou` action, see [this thread](https://wordpress.org/support/topic/suggestion-for-the-faq?replies=5#post-6298810) on the support forum.
205
-
206
- = How can I get a copy of the invoice emailed to the shop manager? =
207
- The easiest way to do this is to just tick the 'new order' box. However, this also means that an invoice will be created for all new orders, also the ones that are never completed.
208
-
209
- Alternatively you can get a (BCC) copy of the completed order email by placing the following filter in your theme's `functions.php` (Some themes have a "custom functions" area in the settings)
210
- Modify the name & email address to your own preferences,
211
-
212
- `
213
- add_filter( 'woocommerce_email_headers', 'mycustom_headers_filter_function', 10, 2);
214
-
215
- function mycustom_headers_filter_function( $headers, $object ) {
216
- if ($object == 'customer_completed_order') {
217
- $headers .= 'BCC: Your name <your@email.com>' . "\r\n"; //just repeat this line again to insert another email address in BCC
218
- }
219
-
220
- return $headers;
221
- }
222
- `
223
-
224
-
225
- = Fatal error: Allowed memory size of ######## bytes exhausted (tried to allocate ### bytes) =
226
-
227
- This usually only happens on batch actions. PDF creation is a memory intensive job, especially if it includes several pages with images. Go to WooCommerce > System Status to check your WP Memory Limit. We recommend setting it to 128mb or more.
228
-
229
- == Screenshots ==
230
-
231
- 1. General settings page
232
- 2. Template settings page
233
- 3. Simple invoice PDF
234
- 4. Simple packing slip PDF
235
-
236
- == Changelog ==
237
-
238
- = 1.5.28 =
239
- * Tweak: the 'Next invoice number' is now stored separately in the database for faster and more reliable retrieval. Circumventing any caching, this should prevent duplicate invoice numbers.
240
- * Fix: Bulk actions plugin conflicts
241
- * Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
242
-
243
- = 1.5.27 =
244
- * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
245
- * Feature: WooCommerce Order Status & Actions Manager emails compatibility
246
- * Feature: Add invoice number to WC REST API
247
- * Fix: Allow positive 'discounts' (price corrections)
248
- * Fix: Discounts rounding
249
- * Translations: Updated Finnish & Portugese & POT
250
-
251
- = 1.5.26 =
252
- * Feature: Automatically list all emails registered in WooCommerce
253
- * Feature: Reset invoice number yearly
254
- * Feature: WooCommerce Chained Products compatibility
255
- * Feature: WooCommerce Product Bundles visibility settings taken into account in invoice
256
- * Fix: Disable PDF creation from trashed order_ids
257
- * Tweak: Alert when no orders selected for bulk export (Props to Dartui!)
258
- * Tweak: PDF invoice settings always under WooCommerce menu (also for premium users)
259
- * Tweak: extra $item_id passed in row class filter
260
- * Translations: Updated Slovenian, Spanish, Dutch & POT file
261
-
262
- = 1.5.24 =
263
- * Hotfix: Subscriptions renewal filter arguments
264
-
265
- = 1.5.23 =
266
- * Fix: WooCommerce Subscriptons 2.0 deprecation notice.
267
- * Tweak: better qTranslate-X support
268
- * Tweak: filter for user privileges check (wpo_wcpdf_check_privs)
269
- * Translations: French translations fix
270
-
271
- = 1.5.22 =
272
- * Fix: Workaround for bug in WPML (which cleared all settings)
273
- * Translation: fixed Polish translation for invoice
274
-
275
- = 1.5.21 =
276
- * Translations: Added Estionan (thanks Tanel!)
277
- * Tweak: WC2.4 compatibility
278
-
279
- = 1.5.20 =
280
- * Feature: Option to 'never' display My Account invoice link
281
- * Fix: Order total for refunds in WC2.4
282
- * Fix: notice when no custom statuses selected for My Account display
283
- * Tweak: Product bundles styles
284
-
285
- = 1.5.19 =
286
- * Fix: Invoice number search (broke other custom searches)
287
-
288
- = 1.5.18 =
289
- * Fix: wpo_wcpdf_item_row_class packing slip filter arguments
290
-
291
- = 1.5.17 =
292
- * Feature: WooCommerce Product Bundles compatibility styles
293
- * Tweak: wpo_wcpdf_item_row_class as filter instead of action
294
-
295
- = 1.5.16 =
296
- * Feature: Search orders by invoice number (note: search on formatted invoice number only works for new orders)
297
- * Feature: Formatted invoice number stored in order
298
- * Tweak: Function parameters added to some of the filters
299
- * Tweak: WooCommerce 2.4 compatibility
300
- * Dev feature: action to add class to items table row (wpo_wcpdf_item_row_class)
301
- * Translations: Swedish updated (thanks Conney!)
302
- * Translations: Norwegian updated
303
-
304
- = 1.5.15 =
305
- * Fix: invoice number padding didn't work for values lower than 3
306
- * Tweak: WPML compatibility filter
307
- * Translations: Updated French (Thanks Nicolas!)
308
-
309
- = 1.5.14 =
310
- * Tweak: Invoice number & date edit fields moved to separate box on order edit page
311
- * Translations: Updated POT & Dutch
312
-
313
- = 1.5.13 =
314
- * Fix: Better address comparison to determine when to display alternate address
315
- * Tweak: Filter N/A addresses
316
- * Tweak: Use WooCommerce function for 2.3 discounts
317
- * Translations: Czech Updated (Thanks Ivo!)
318
- * Translations: French (minor fixes)
319
-
320
- = 1.5.12 =
321
- * Translations: added Danish, Updated POT & Italian
322
-
323
- = 1.5.11 =
324
- * Fix: Product text attributes (now checks key too)
325
- * Fix: Status page upload explanation typos
326
-
327
- = 1.5.10 =
328
- * Fix: Double check to make sure plugin doesn't attach to user emails
329
-
330
- = 1.5.9 =
331
- * Feature: Shorthand function to display product attributes: `$wpo_wcpdf->get_product_attribute( $attribute_name, $product )`
332
-
333
- = 1.5.8 =
334
- * Feature: disable invoice for free orders
335
- * Feature: action to insert data before & after item meta
336
- * Tweak: Added classes to sku & weight
337
- * Tweak: Hide payment method from totals (already shown in template)
338
- * Translations: Updated POT & Dutch
339
-
340
- = 1.5.7 =
341
- * Feature: Setting to show email address & phone number on invoice or packing slip (does not work on custom templates based on previous versions!)
342
-
343
- = 1.5.6 =
344
- * Feature: Setting to show shipping address on invoice (does not work on custom templates based on previous versions!)
345
- * Feature: My Account invoice download setting
346
- * Feature: several new template actions
347
- * Tweak: WooCommerce Bookings compatibility
348
- * Tweak: Gerenal stylesheet cleanup
349
- * Fix: temp path check/error on settings page
350
- * Fix: Document titles for credit notes and proforma (Pro)
351
- * Fix: Discount including tax
352
- * Fix: Special characters on item meta (requires WooCommerce 2.3.6)
353
- * Translations: Missing text domain on several strings
354
- * Translations: Updated POT & Dutch
355
-
356
- = 1.5.5 =
357
- * Fix: Check for incomplete line tax data (Subscriptions compatibility)
358
- * Fix: More precise template path instructions
359
- * Fix: duplicate stylesheet filter
360
- * Fix: Always prefer original order's billing address for refunds (WooCommerce EU VAT Number compatibility)
361
- * Translations: Updated German (MwSt. instead of formal Ust.)
362
- * Translations: Updated Dutch
363
-
364
- = 1.5.4 =
365
- * Tweak: include plugin version in style/script includes
366
- * Tweak: upload code cleanup
367
- * Fix: Parent invoice number (for Credit Notes in professional extension)
368
-
369
- = 1.5.3 =
370
- * Feature: add original order date value to order date filter
371
- * Feature: Work with line_tax_data when available
372
- * Feature: pass item_id to items
373
- * Tweak: later check for woocommerce active
374
- * Fix: do not try to validate empty settings (Status page settings)
375
- * Translations: Fixed Dutch typo
376
-
377
- = 1.5.2 =
378
- * Fix: fatal error when trying to activate with WooCommerce not installed yet.
379
- * Tweak: indentation fix on the Simple template
380
-
381
- = 1.5.1 =
382
- * Fix: prevent errors when upgrading
383
-
384
- = 1.5.0 =
385
- * Feature: All temporary files are now stored centrally in the WP uploads folder.
386
- * Feature: Debug settings in status panel (output errors & output to HTML)
387
- * Feature: Compatibility filter for WooCommerce Subscriptions (prevents duplicate invoice numbers)
388
- * Tweak: Pass order to totals filters
389
- * Translations: Updated POT
390
- * Translations: Updated Italian (Thanks Astrid!)
391
- * Translations: Updated Dutch
392
- * FAQ: instructions for placing a link on the thank you page
393
-
394
- = 1.4.14 =
395
- * Fix: fatal error when user registers at checkout (applies to credit notes only)
396
- * Translations: Updated German (Thanks Dietmar!)
397
- * Translations: Place your custom translations in wp-content/languages/woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-LOCALE.mo to protect them from being overwritten by plugin updates.
398
-
399
- = 1.4.13 =
400
- * Feature: use separate file for all your template specific functions (template-functions.php)
401
- * Translations: Added Slovenian (thanks gregy1403!)
402
- * Translations: Updated Norwegian & Dutch.
403
- * Translations: Added Japanese - needs custom font!
404
- * FAQ: instructions on how to use custom fonts
405
-
406
- = 1.4.12 =
407
- * Fix: issues with post parent objects (WC2.1 and older)
408
-
409
- = 1.4.11 =
410
- * Small fix: bulk actions for specific i18n configurations
411
- * Tweak: total row key used as class in Simple template
412
-
413
- = 1.4.10 =
414
- * Fix: Invoice not attaching
415
- * Translations: Updated POT file
416
- * Translations: Updated Dutch, Norwegian, Polish, Brazilian Portugese, Romanian, Russian, Slovak, Spanish & Ukrainian (Many thanks to all the translators!)
417
- * Templates: added action hooks for easier customizations (`wpo_wcpdf_before_order_details`, `wpo_wcpdf_after_order_details`, `wpo_wcpdf_invoice_title` & `wpo_wcpdf_packing_slip_title`)
418
-
419
- = 1.4.9 =
420
- * Feature: Order number and date are now displayed by default in the Simple template (invoice number and date still optional)
421
- * Feature: Display Customer/Order notes with a simple shorthand (see FAQ)
422
- * Translations: Added Brazilian Portugese (thanks Victor Debone!)
423
- * Tweak: Fail more gracefully when there are errors during PDF generation
424
- * Tweak: added template type class to template output body
425
- * Tweak: cleaned up Simple template style.css
426
-
427
- = 1.4.8 =
428
- * Translations: Added Finnish (Thanks Sami Mäkelä/Contrast.fi!)
429
-
430
- = 1.4.7 =
431
- * Fix: check if image file exists locally, fallback to url if not (CDN compatibility)
432
- * Fix: make deleting invoice date possible
433
- * Fix: correct tmp folder check on status page
434
- * Translations: updated po/mo files
435
- * Tweak: changed settings capability requirement to `manage_woocommerce` (was: `manage_options`)
436
- * Tweak: better email attachment function
437
- * Tweak: prevent footer overlap (Simple template)
438
- * Tweak: fallback if `glob()` is not allowed on the server
439
- * Tweak: better custom template instructions (reflects path to actual (child-)theme)
440
-
441
- = 1.4.6 =
442
- * HOTFIX: WooCommerce 2.2 compatibility fix
443
- * Filter for PDF temp folder (wpo_wcpdf_tmp_path)
444
-
445
- = 1.4.5 =
446
- * Fix: Double date conversion for order date on invoice number filter (to avoid i18n date issues)
447
- * Fix: Template selector reset after update
448
- * Translations: added Norwegian (Thanks Aleksander!)
449
-
450
- = 1.4.4 =
451
- * Feature: Editable invoice date per order/invoice.
452
- * Feature: HTML is now allowed in footer and other settings fields.
453
- * Translations: Updated German (Thanks Nadine!)
454
- * Fix: template paths are now saved relative to the site base path (ABSPATH) to prevent errors when moving to another server
455
- * Tweak: Changed bulk action hook for better theme compatibility
456
- * Tweak: Newlines in custom checkout fields
457
-
458
- = 1.4.3 =
459
- * Feature: Added function to call custom fields more easily (see FAQ)
460
- * Feature: Change the my account button text via a filter (wpo_wcpdf_myaccount_button_text)
461
- * Translations: Added Danish (Thanks Mads!)
462
- * Tweak: only load PDF engine if it's not already loaded by another plugin
463
-
464
- = 1.4.2 =
465
- * Fix: Don't create invoice number when exporting packing slips
466
- * Fix: Division by zero for 0 quantity items
467
-
468
- = 1.4.1 =
469
- * Translations: Added Polish (Thanks Mike!)
470
- * Fix: Invoice number formatting notices in debug mode
471
-
472
- = 1.4.0 =
473
- * Feature: Invoice numbers can now be given a prefix, suffix or padding on the settings page!
474
- * Filter: `wpo_wcpdf_email_allowed_statuses` to attach pdf to custom order status emails
475
- * Tweak: Sequential Order Numbers Pro compatibility
476
- * Tweak: Filenames are now automatically sanitized to prevent issues with illegal characters
477
-
478
- = 1.3.2 =
479
- * Fix: error on wpo_wcpdf_email_attachment filter when $pdf_path not set
480
-
481
- = 1.3.1 =
482
- * Fix: invoice number was cleared when Order Actions were being used when an invoice number was not set
483
- * Translations: Updated Slovak (Thanks Jozef!)
484
- * Translations: Added Czech (Thanks CubiQ!)
485
-
486
- = 1.3.0 =
487
- * Feature: Added 'status' panel for better problem diagnosis
488
- * Tweak: split create & get invoice number calls to prevent slow database calls from causing number skipping
489
- * Translations: Added Romanian (Thanks Leonardo!)
490
- * Translations: Added Slovak (Thanks Oleg!)
491
-
492
- = 1.2.13 =
493
- * Feature: added filter for custom email attachment condition (wpo_wcpdf_custom_email_condition)
494
- * Fix: warning for tax implode
495
-
496
- = 1.2.12 =
497
- * Fix: hyperlink underline (was more like a strikethrough)
498
-
499
- = 1.2.11 =
500
- * Translations: Fixed German spelling error
501
- * Translations: Updated Swedish (Thanks Fredrik!)
502
-
503
- = 1.2.10 =
504
- * Translations: Added Swedish (Thanks Jonathan!)
505
- * Fix: Line-height issue (on some systems, the space between lines was very high)
506
-
507
- = 1.2.9 =
508
- * Fix: bug where 'standard' tax class would not display in some cases
509
- * Fix: bug that caused the totals to jump for some font sizes
510
- * Fix: WC2.1 deprecated totals function
511
- * Fix: If multiple taxes were set up with the same name, only one would display (Simple template was not affected)
512
-
513
- = 1.2.8 =
514
- * Template: Body line-height defined to prevent character jumping with italic texts
515
- * Fix: Open Sans now included in plugin package (fixes font issues for servers with allow_url_fopen disabled)
516
-
517
- = 1.2.7 =
518
- * Translations: POT, DE & NL updated
519
- * Fix: Removed stray span tag in totals table
520
-
521
- = 1.2.6 =
522
- * Translations: Spanish update (thanks prepu!)
523
- * Fix: More advanced checks to determine if a customer can download the invoice (including a status filter)
524
-
525
- = 1.2.5 =
526
- * Feature: Optional Invoice Number column for the orders listing
527
- * Feature: Better support for international characters
528
- * Translations: Added Russian & Ukrainian translation (thanks Oleg!)
529
- * Translations: Updated Spanish (Thanks Manuel!) and Dutch translations & POT file
530
- * Tweak: Memory limit notice
531
- * Tweak: Filename name now includes invoice number (when configured in the settings)
532
-
533
- = 1.2.4 =
534
- * Feature: Set which type of emails you want to attach the invoice to
535
-
536
- = 1.2.3 =
537
- * Feature: Manually edit invoice number on the edit order screen
538
- * Feature: Set the first (/next) invoice number on the settings screen
539
- * Fix: Bug where invoice number would be generated twice due to slow database calls
540
- * Fix: php strict warnings
541
-
542
- = 1.2.2 =
543
- * Feature: Simple template now uses Open Sans to include more international special characters
544
- * Feature: Implemented filters for paper size & orientation ([read here](http://wordpress.org/support/topic/select-a5-paper-size-for-packing-slips?replies=5#post-5211129))
545
- * Tweak: PDF engine updated (dompdf 0.6.0)
546
- * Tweak: Download PDF link on the my account page is now only shown when an invoice is already created by the admin or automatically, to prevent unwanted invoice created (creating problems with european laws).
547
-
548
- = 1.2.1 =
549
- * Fix: shipping & fees functions didn't output correctly with the tax set to 'incl'
550
-
551
- = 1.2.0 =
552
- * Feature: Sequential invoice numbers (set upon invoice creation).
553
- * Feature: Invoice date (set upon invoice creation).
554
-
555
- = 1.1.6 =
556
- * Feature: Hungarian translations added - thanks Joseph!
557
- * Tweak: Better debug code.
558
- * Tweak: Error reporting when templates not found.
559
- * Fix: tax rate calculation for free items.
560
-
561
- = 1.1.5 =
562
- * Feature: German translations added - thanks Christian!
563
- * Fix: dompdf 0.6.0 proved to be less stable, so switching back to beta3 for now.
564
-
565
- = 1.1.4 =
566
- * Fix: Template paths on windows servers were not properly saved (stripslashes), resulting in an empty output.
567
-
568
- = 1.1.3 =
569
- * Feature: PDF engine (dompdf) updated to 0.6.0 for better stability and utf-8 support.
570
- * Tweak: Local server path is used for header image for better compatibility with server settings.
571
- * Fix: several small bugs.
572
-
573
- = 1.1.2 =
574
- * Feature: Totals can now be called with simpler template functions
575
- * Feature: Italian translations - thanks max66max!
576
- * Tweak: improved memory performance
577
-
578
- = 1.1.1 =
579
- * Feature: French translations - thanks Guillaume!
580
-
581
- = 1.1.0 =
582
- * Feature: Fees can now also be called ex. VAT
583
- * Feature: Invoices can now be downloaded from the My Account page
584
- * Feature: Spanish translation & POT file included
585
- * Fix: ternary statements that caused an error
586
-
587
- = 1.0.1 =
588
- * Tweak: Packing slip now displays shipping address instead of billing address
589
- * Tweak: Variation data is now displayed by default
590
-
591
- = 1.0.0 =
592
- * First release
593
-
594
- == Upgrade Notice ==
595
-
596
- = 1.5 =
597
- Version 1.5 changes where temporary files are stored - everything is now stored centrally in the WP uploads folder. For backwards compatibility, this feature is turned off by default, but we recommend to use the new folders. Check the plugin Status panel for more information!
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: pomegranate
3
+ Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
4
+ Requires at least: 3.5
5
+ Tested up to: 4.4.2
6
+ Stable tag: 1.5.29
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Create, print & automatically email PDF invoices & packing slips for WooCommerce orders.
11
+
12
+ == Description ==
13
+
14
+ This WooCommerce extension automatically adds a PDF invoice to the order confirmation emails sent out to your customers. Includes a basic template (additional templates are available from [WP Overnight](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)) as well as the possibility to modify/create your own templates. In addition, you can choose to download or print invoices and packing slips from the WooCommerce order admin.
15
+
16
+ = Main features =
17
+ * Automatically attach invoice PDF to WooCommerce emails of your choice
18
+ * Download the PDF invoice / packing slip from the order admin page
19
+ * Generate PDF invoices / packings slips in bulk
20
+ * **Fully customizable** HTML/CSS invoice templates
21
+ * Download invoices from the My Account page
22
+ * Sequential invoice numbers - with custom formatting
23
+ * **Available in: Czech, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese (see FAQ for adding custom fonts!), Norwegian, Polish, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish & Ukrainian**
24
+
25
+ In addition to this, we offer several premium extensions:
26
+
27
+ * Create/email PDF Proforma Invoices, Credit Notes (for Refunds), email Packing Slips & more with [WooCommerce PDF Invoices & Packing Slips Professional](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
28
+ * Upload all invoices automatically to Dropbox with [WooCommerce PDF Invoices & Packing Slips to Dropbox](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-dropbox/)
29
+ * Automatically send new orders or packing slips to your printer, as soon as the customer orders! [WooCommerce Automatic Order Printing](https://www.simbahosting.co.uk/s3/product/woocommerce-automatic-order-printing/?affiliates=2) (from our partners at Simba Hosting)
30
+ * More advanced & stylish templates with [WooCommerce PDF Invoices & Packing Slips Premium Templates](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)
31
+
32
+ = Fully customizable =
33
+ In addition to a number of default settings (including a custom header/logo) and several layout fields that you can use out of the box, the plugin contains HTML/CSS based templates that allow for customization & full control over the PDF output. Copy the templates to your theme folder and you don't have to worry that your customizations will be overwritten when you update the plugin.
34
+
35
+ * Insert customer header image/logo
36
+ * Modify shop data / footer / disclaimer etc. on the invoices & packing slips
37
+ * Select paper size (Letter or A4)
38
+ * Translation ready
39
+
40
+ == Installation ==
41
+
42
+ = Minimum Requirements =
43
+
44
+ * WooCommerce 2.0 or later
45
+ * WordPress 3.5 or later
46
+
47
+ = Automatic installation =
48
+ Automatic installation is the easiest option as WordPress handles the file transfers itself and you don't even need to leave your web browser. To do an automatic install of WooCommerce PDF Invoices & Packing Slips, log in to your WordPress admin panel, navigate to the Plugins menu and click Add New.
49
+
50
+ In the search field type "WooCommerce PDF Invoices & Packing Slips" and click Search Plugins. You can install it by simply clicking Install Now. After clicking that link you will be asked if you're sure you want to install the plugin. Click yes and WordPress will automatically complete the installation. After installation has finished, click the 'activate plugin' link.
51
+
52
+ = Manual installation via the WordPress interface =
53
+ 1. Download the plugin zip file to your computer
54
+ 2. Go to the WordPress admin panel menu Plugins > Add New
55
+ 3. Choose upload
56
+ 4. Upload the plugin zip file, the plugin will now be installed
57
+ 5. After installation has finished, click the 'activate plugin' link
58
+
59
+ = Manual installation via FTP =
60
+ 1. Download the plugin file to your computer and unzip it
61
+ 2. Using an FTP program, or your hosting control panel, upload the unzipped plugin folder to your WordPress installation's wp-content/plugins/ directory.
62
+ 3. Activate the plugin from the Plugins menu within the WordPress admin.
63
+
64
+ == Frequently Asked Questions ==
65
+
66
+ Make sure to check out [WooCommerce PDF Invoices & Packing Slips documentation](http://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/) on our site - it covers most of the questions below (and more!) in more detail!
67
+
68
+ = How do I create my own custom template? =
69
+
70
+ Copy the files from `wp-content/plugins/woocommerce-pdf-invoices-packing-slips/templates/pdf/Simple/` to your (child) theme in `wp-content/themes/yourtheme/woocommerce/pdf/yourtemplate` and customize them there. The new template will show up as 'yourtemplate' (the folder name) in the settings panel.
71
+
72
+ = Where can I find more templates? =
73
+
74
+ Go to [wpovernight.com](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/) to checkout more templates! These include templates with more tax details and product thumbnails. Need a custom templates? Contact us at support@wpovernight.com for more information.
75
+
76
+ = Can I create/send a proforma invoice or a credit note? =
77
+ This is a feature of our Professional extension, which can be found at [wpovernight.com](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
78
+
79
+ = Can I contribute to the code? =
80
+ You're more than welcome! This plugin is hosted on github, where you can post issues or make pull requests.
81
+ https://github.com/wpovernight/woocommerce-pdf-invoices-packing-slips
82
+
83
+ = My language is not included, how can I contribute? =
84
+
85
+ This plugin is translation ready, which means that you can translate it using standard WordPress methods.
86
+
87
+ 1. Download POEdit at (http://www.poedit.net/download.php)
88
+ 2. Open POEdit
89
+ 3. File > New from POT
90
+ 4. Open wpo_wcpdf.pot (from `woocommerce-pdf-invoices-packing-slips/languages/`)
91
+ 5. A popup will ask you for your language
92
+ 6. This step is a bit tricky, configuring the plurals. Somehow the settings can't be copied from the pot. Go to Catalogue > Preferences. Then enter nplurals=2; plural=n != 1; in the custom expression field
93
+ 7. Enter the translations. invoice and packing-slip now have two translation fields, single & plural. Note that this is a filename, so replace spaces with a - just to be sure!
94
+ 8. Save as `wpo_wcpdf-xx_XX.po`, where you replace xx_XX with your language code & country code suffix (da_DK, pl_PL, de_DE etc.)
95
+
96
+ = How can I use my own font? =
97
+ Although the plugin supports webfonts, this is somewhat limited and has a lot of caveats, read [this thread](https://wordpress.org/support/topic/webfonts-within-a-custom-template-not-rendering-in-pdf?replies=4#post-5395442) on the forum.
98
+ Some languages (Japanese, Chinese, etc.) are not supported by the default font included with the plugin, in this case a custom font is required.
99
+ The best method is to create a custom template first (see above), then add a `fonts/` folder to that template and use the following code (replace the font names/filenames) to load the font in the style.css from the pdf template:
100
+ `
101
+ <?php global $wpo_wcpdf;?>
102
+ /* Load font */
103
+ @font-face {
104
+ font-family: 'MyFont';
105
+ font-style: normal;
106
+ font-weight: normal;
107
+ src: local('MyFont'), local('MyFont'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont.ttf) format('truetype');
108
+ }
109
+ @font-face {
110
+ font-family: 'MyFont';
111
+ font-style: normal;
112
+ font-weight: bold;
113
+ src: local('MyFont Bold'), local('MyFont-Bold'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-bold.ttf) format('truetype');
114
+ }
115
+ @font-face {
116
+ font-family: 'MyFont';
117
+ font-style: italic;
118
+ font-weight: normal;
119
+ src: local('MyFont Italic'), local('MyFont-Italic'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-italic.ttf) format('truetype');
120
+ }
121
+ @font-face {
122
+ font-family: 'MyFont';
123
+ font-style: italic;
124
+ font-weight: bold;
125
+ src: local('MyFont Bold Italic'), local('MyFont-BoldItalic'), url(<?php echo $wpo_wcpdf->export->template_path; ?>/fonts/myfont-bolditalic.ttf) format('truetype');
126
+ }
127
+ `
128
+ then make sure you assign that font family to the body or other elements of the template:
129
+ `
130
+ font-family: 'MyFont';
131
+ `
132
+
133
+ Some notes:
134
+
135
+ * Only TTF fonts are supported.
136
+ * You can't use numeric font weights (like 700 instead of bold)!
137
+ * Avoid spaces or special characters in the font filenames.
138
+ * I have found that not all servers cope well with the font paths. If this is the case with your font, try to put the font in the root of your site and put that in the font url (i.e. `url(http://yoursite.com/fonts/myfont-italic.ttf)` )
139
+
140
+ Some font links:
141
+
142
+ * Japanese - http://ipafont.ipa.go.jp/index.html
143
+ * Chinese - http://www.study-area.org/apt/firefly-font/
144
+
145
+ = How can I display the HTML/CSS source for debugging/developing templates? =
146
+ There's a setting on the Status tab of the settings page that allows you to toggle HTML output. Don't forget to turn if off after you're done testing!
147
+
148
+ = How can I display custom fields in the invoice or packing slip? =
149
+ First, you need to create a custom template following instructions from the first item in this FAQ.
150
+ Then place the following snippet where you would like the custom field to appear:
151
+
152
+ `
153
+ <?php $wpo_wcpdf->custom_field('custom_fieldname', 'Custom field:'); ?>
154
+ `
155
+
156
+ Where you replace 'custom_fieldname' with the name of the field you want to display, and 'Custom field' with the label. The plugin only displays the field when it contains data. If you also want to display the label when the field is empty, you can pass a third parameter (true), like this:
157
+
158
+ `
159
+ <?php $wpo_wcpdf->custom_field('custom_fieldname', 'Custom field:', true); ?>
160
+ `
161
+
162
+ = How can I display order notes in the invoice or packing slip? =
163
+ First, you need to create a custom template following instructions from the first item in this FAQ.
164
+ Then place the following snippet where you would like the order notes to appear:
165
+
166
+ `
167
+ <?php $wpo_wcpdf->order_notes(); ?>
168
+ `
169
+
170
+ if you want to display all order notes, including the (private) admin notes, use:
171
+ `
172
+ <?php $wpo_wcpdf->order_notes('all'); ?>
173
+ `
174
+
175
+ = How do can I modify the pdf filename? =
176
+ You can do this via a filter in your theme's `functions.php` (Some themes have a "custom functions" area in the settings).
177
+
178
+ Here's a simple example for putting your shop name in front of the filname.
179
+ `
180
+ add_filter( 'wpo_wcpdf_filename', 'wpo_wcpdf_custom_filename', 10, 4 );
181
+ function wpo_wcpdf_custom_filename( $filename, $template_type, $order_ids, $context ) {
182
+ // prepend your shopname to the file
183
+ $new_filename = 'myshopname_' . $filename;
184
+
185
+ return $new_filename;
186
+ }
187
+ `
188
+ You can also use the $template_type ('invoice' or 'packing-slip'), $order_ids (single array) or $context ('download' or 'attachment') variables to make more complex rules for the filename.
189
+
190
+ = How can I add a download link to the invoice on the Thank you page? =
191
+ You can do this with an action in your theme's `functions.php` (Some themes have a "custom functions" area in the settings). Note that due to security restrictions, this will only work for registered/logged in users!
192
+
193
+ `
194
+ add_filter('woocommerce_thankyou_order_received_text', 'wpo_wcpdf_thank_you_link', 10, 2);
195
+ function wpo_wcpdf_thank_you_link( $text, $order ) {
196
+ if ( is_user_logged_in() ) {
197
+ $pdf_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=generate_wpo_wcpdf&template_type=invoice&order_ids=' . $order->id . '&my-account'), 'generate_wpo_wcpdf' );
198
+ $text .= '<p><a href="'.esc_attr($pdf_url).'">Download a printable invoice / payment confirmation (PDF format)</a></p>';
199
+ }
200
+ return $text;
201
+ }
202
+ `
203
+
204
+ alternatively, you can hook this text to the `woocommerce_thankyou` action, see [this thread](https://wordpress.org/support/topic/suggestion-for-the-faq?replies=5#post-6298810) on the support forum.
205
+
206
+ = How can I get a copy of the invoice emailed to the shop manager? =
207
+ The easiest way to do this is to just tick the 'new order' box. However, this also means that an invoice will be created for all new orders, also the ones that are never completed.
208
+
209
+ Alternatively you can get a (BCC) copy of the completed order email by placing the following filter in your theme's `functions.php` (Some themes have a "custom functions" area in the settings)
210
+ Modify the name & email address to your own preferences,
211
+
212
+ `
213
+ add_filter( 'woocommerce_email_headers', 'mycustom_headers_filter_function', 10, 2);
214
+
215
+ function mycustom_headers_filter_function( $headers, $object ) {
216
+ if ($object == 'customer_completed_order') {
217
+ $headers .= 'BCC: Your name <your@email.com>' . "\r\n"; //just repeat this line again to insert another email address in BCC
218
+ }
219
+
220
+ return $headers;
221
+ }
222
+ `
223
+
224
+
225
+ = Fatal error: Allowed memory size of ######## bytes exhausted (tried to allocate ### bytes) =
226
+
227
+ This usually only happens on batch actions. PDF creation is a memory intensive job, especially if it includes several pages with images. Go to WooCommerce > System Status to check your WP Memory Limit. We recommend setting it to 128mb or more.
228
+
229
+ == Screenshots ==
230
+
231
+ 1. General settings page
232
+ 2. Template settings page
233
+ 3. Simple invoice PDF
234
+ 4. Simple packing slip PDF
235
+
236
+ == Changelog ==
237
+
238
+ = 1.5.29 =
239
+ * Translations: Added Croation (Thanks Neven/Spine ICT!), updated French (Thanks Sabra!)
240
+ * Tweak: filter shop address before checking if it's empty
241
+ * Dev: added $order to `wpo_wcpdf_template_file` filter
242
+
243
+ = 1.5.28 =
244
+ * Tweak: the 'Next invoice number' is now stored separately in the database for faster and more reliable retrieval. Circumventing any caching, this should prevent duplicate invoice numbers.
245
+ * Fix: Bulk actions plugin conflicts
246
+ * Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
247
+
248
+ = 1.5.27 =
249
+ * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
250
+ * Feature: WooCommerce Order Status & Actions Manager emails compatibility
251
+ * Feature: Add invoice number to WC REST API
252
+ * Fix: Allow positive 'discounts' (price corrections)
253
+ * Fix: Discounts rounding
254
+ * Translations: Updated Finnish & Portugese & POT
255
+
256
+ = 1.5.26 =
257
+ * Feature: Automatically list all emails registered in WooCommerce
258
+ * Feature: Reset invoice number yearly
259
+ * Feature: WooCommerce Chained Products compatibility
260
+ * Feature: WooCommerce Product Bundles visibility settings taken into account in invoice
261
+ * Fix: Disable PDF creation from trashed order_ids
262
+ * Tweak: Alert when no orders selected for bulk export (Props to Dartui!)
263
+ * Tweak: PDF invoice settings always under WooCommerce menu (also for premium users)
264
+ * Tweak: extra $item_id passed in row class filter
265
+ * Translations: Updated Slovenian, Spanish, Dutch & POT file
266
+
267
+ = 1.5.24 =
268
+ * Hotfix: Subscriptions renewal filter arguments
269
+
270
+ = 1.5.23 =
271
+ * Fix: WooCommerce Subscriptons 2.0 deprecation notice.
272
+ * Tweak: better qTranslate-X support
273
+ * Tweak: filter for user privileges check (wpo_wcpdf_check_privs)
274
+ * Translations: French translations fix
275
+
276
+ = 1.5.22 =
277
+ * Fix: Workaround for bug in WPML (which cleared all settings)
278
+ * Translation: fixed Polish translation for invoice
279
+
280
+ = 1.5.21 =
281
+ * Translations: Added Estionan (thanks Tanel!)
282
+ * Tweak: WC2.4 compatibility
283
+
284
+ = 1.5.20 =
285
+ * Feature: Option to 'never' display My Account invoice link
286
+ * Fix: Order total for refunds in WC2.4
287
+ * Fix: notice when no custom statuses selected for My Account display
288
+ * Tweak: Product bundles styles
289
+
290
+ = 1.5.19 =
291
+ * Fix: Invoice number search (broke other custom searches)
292
+
293
+ = 1.5.18 =
294
+ * Fix: wpo_wcpdf_item_row_class packing slip filter arguments
295
+
296
+ = 1.5.17 =
297
+ * Feature: WooCommerce Product Bundles compatibility styles
298
+ * Tweak: wpo_wcpdf_item_row_class as filter instead of action
299
+
300
+ = 1.5.16 =
301
+ * Feature: Search orders by invoice number (note: search on formatted invoice number only works for new orders)
302
+ * Feature: Formatted invoice number stored in order
303
+ * Tweak: Function parameters added to some of the filters
304
+ * Tweak: WooCommerce 2.4 compatibility
305
+ * Dev feature: action to add class to items table row (wpo_wcpdf_item_row_class)
306
+ * Translations: Swedish updated (thanks Conney!)
307
+ * Translations: Norwegian updated
308
+
309
+ = 1.5.15 =
310
+ * Fix: invoice number padding didn't work for values lower than 3
311
+ * Tweak: WPML compatibility filter
312
+ * Translations: Updated French (Thanks Nicolas!)
313
+
314
+ = 1.5.14 =
315
+ * Tweak: Invoice number & date edit fields moved to separate box on order edit page
316
+ * Translations: Updated POT & Dutch
317
+
318
+ = 1.5.13 =
319
+ * Fix: Better address comparison to determine when to display alternate address
320
+ * Tweak: Filter N/A addresses
321
+ * Tweak: Use WooCommerce function for 2.3 discounts
322
+ * Translations: Czech Updated (Thanks Ivo!)
323
+ * Translations: French (minor fixes)
324
+
325
+ = 1.5.12 =
326
+ * Translations: added Danish, Updated POT & Italian
327
+
328
+ = 1.5.11 =
329
+ * Fix: Product text attributes (now checks key too)
330
+ * Fix: Status page upload explanation typos
331
+
332
+ = 1.5.10 =
333
+ * Fix: Double check to make sure plugin doesn't attach to user emails
334
+
335
+ = 1.5.9 =
336
+ * Feature: Shorthand function to display product attributes: `$wpo_wcpdf->get_product_attribute( $attribute_name, $product )`
337
+
338
+ = 1.5.8 =
339
+ * Feature: disable invoice for free orders
340
+ * Feature: action to insert data before & after item meta
341
+ * Tweak: Added classes to sku & weight
342
+ * Tweak: Hide payment method from totals (already shown in template)
343
+ * Translations: Updated POT & Dutch
344
+
345
+ = 1.5.7 =
346
+ * Feature: Setting to show email address & phone number on invoice or packing slip (does not work on custom templates based on previous versions!)
347
+
348
+ = 1.5.6 =
349
+ * Feature: Setting to show shipping address on invoice (does not work on custom templates based on previous versions!)
350
+ * Feature: My Account invoice download setting
351
+ * Feature: several new template actions
352
+ * Tweak: WooCommerce Bookings compatibility
353
+ * Tweak: Gerenal stylesheet cleanup
354
+ * Fix: temp path check/error on settings page
355
+ * Fix: Document titles for credit notes and proforma (Pro)
356
+ * Fix: Discount including tax
357
+ * Fix: Special characters on item meta (requires WooCommerce 2.3.6)
358
+ * Translations: Missing text domain on several strings
359
+ * Translations: Updated POT & Dutch
360
+
361
+ = 1.5.5 =
362
+ * Fix: Check for incomplete line tax data (Subscriptions compatibility)
363
+ * Fix: More precise template path instructions
364
+ * Fix: duplicate stylesheet filter
365
+ * Fix: Always prefer original order's billing address for refunds (WooCommerce EU VAT Number compatibility)
366
+ * Translations: Updated German (MwSt. instead of formal Ust.)
367
+ * Translations: Updated Dutch
368
+
369
+ = 1.5.4 =
370
+ * Tweak: include plugin version in style/script includes
371
+ * Tweak: upload code cleanup
372
+ * Fix: Parent invoice number (for Credit Notes in professional extension)
373
+
374
+ = 1.5.3 =
375
+ * Feature: add original order date value to order date filter
376
+ * Feature: Work with line_tax_data when available
377
+ * Feature: pass item_id to items
378
+ * Tweak: later check for woocommerce active
379
+ * Fix: do not try to validate empty settings (Status page settings)
380
+ * Translations: Fixed Dutch typo
381
+
382
+ = 1.5.2 =
383
+ * Fix: fatal error when trying to activate with WooCommerce not installed yet.
384
+ * Tweak: indentation fix on the Simple template
385
+
386
+ = 1.5.1 =
387
+ * Fix: prevent errors when upgrading
388
+
389
+ = 1.5.0 =
390
+ * Feature: All temporary files are now stored centrally in the WP uploads folder.
391
+ * Feature: Debug settings in status panel (output errors & output to HTML)
392
+ * Feature: Compatibility filter for WooCommerce Subscriptions (prevents duplicate invoice numbers)
393
+ * Tweak: Pass order to totals filters
394
+ * Translations: Updated POT
395
+ * Translations: Updated Italian (Thanks Astrid!)
396
+ * Translations: Updated Dutch
397
+ * FAQ: instructions for placing a link on the thank you page
398
+
399
+ = 1.4.14 =
400
+ * Fix: fatal error when user registers at checkout (applies to credit notes only)
401
+ * Translations: Updated German (Thanks Dietmar!)
402
+ * Translations: Place your custom translations in wp-content/languages/woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-LOCALE.mo to protect them from being overwritten by plugin updates.
403
+
404
+ = 1.4.13 =
405
+ * Feature: use separate file for all your template specific functions (template-functions.php)
406
+ * Translations: Added Slovenian (thanks gregy1403!)
407
+ * Translations: Updated Norwegian & Dutch.
408
+ * Translations: Added Japanese - needs custom font!
409
+ * FAQ: instructions on how to use custom fonts
410
+
411
+ = 1.4.12 =
412
+ * Fix: issues with post parent objects (WC2.1 and older)
413
+
414
+ = 1.4.11 =
415
+ * Small fix: bulk actions for specific i18n configurations
416
+ * Tweak: total row key used as class in Simple template
417
+
418
+ = 1.4.10 =
419
+ * Fix: Invoice not attaching
420
+ * Translations: Updated POT file
421
+ * Translations: Updated Dutch, Norwegian, Polish, Brazilian Portugese, Romanian, Russian, Slovak, Spanish & Ukrainian (Many thanks to all the translators!)
422
+ * Templates: added action hooks for easier customizations (`wpo_wcpdf_before_order_details`, `wpo_wcpdf_after_order_details`, `wpo_wcpdf_invoice_title` & `wpo_wcpdf_packing_slip_title`)
423
+
424
+ = 1.4.9 =
425
+ * Feature: Order number and date are now displayed by default in the Simple template (invoice number and date still optional)
426
+ * Feature: Display Customer/Order notes with a simple shorthand (see FAQ)
427
+ * Translations: Added Brazilian Portugese (thanks Victor Debone!)
428
+ * Tweak: Fail more gracefully when there are errors during PDF generation
429
+ * Tweak: added template type class to template output body
430
+ * Tweak: cleaned up Simple template style.css
431
+
432
+ = 1.4.8 =
433
+ * Translations: Added Finnish (Thanks Sami Mäkelä/Contrast.fi!)
434
+
435
+ = 1.4.7 =
436
+ * Fix: check if image file exists locally, fallback to url if not (CDN compatibility)
437
+ * Fix: make deleting invoice date possible
438
+ * Fix: correct tmp folder check on status page
439
+ * Translations: updated po/mo files
440
+ * Tweak: changed settings capability requirement to `manage_woocommerce` (was: `manage_options`)
441
+ * Tweak: better email attachment function
442
+ * Tweak: prevent footer overlap (Simple template)
443
+ * Tweak: fallback if `glob()` is not allowed on the server
444
+ * Tweak: better custom template instructions (reflects path to actual (child-)theme)
445
+
446
+ = 1.4.6 =
447
+ * HOTFIX: WooCommerce 2.2 compatibility fix
448
+ * Filter for PDF temp folder (wpo_wcpdf_tmp_path)
449
+
450
+ = 1.4.5 =
451
+ * Fix: Double date conversion for order date on invoice number filter (to avoid i18n date issues)
452
+ * Fix: Template selector reset after update
453
+ * Translations: added Norwegian (Thanks Aleksander!)
454
+
455
+ = 1.4.4 =
456
+ * Feature: Editable invoice date per order/invoice.
457
+ * Feature: HTML is now allowed in footer and other settings fields.
458
+ * Translations: Updated German (Thanks Nadine!)
459
+ * Fix: template paths are now saved relative to the site base path (ABSPATH) to prevent errors when moving to another server
460
+ * Tweak: Changed bulk action hook for better theme compatibility
461
+ * Tweak: Newlines in custom checkout fields
462
+
463
+ = 1.4.3 =
464
+ * Feature: Added function to call custom fields more easily (see FAQ)
465
+ * Feature: Change the my account button text via a filter (wpo_wcpdf_myaccount_button_text)
466
+ * Translations: Added Danish (Thanks Mads!)
467
+ * Tweak: only load PDF engine if it's not already loaded by another plugin
468
+
469
+ = 1.4.2 =
470
+ * Fix: Don't create invoice number when exporting packing slips
471
+ * Fix: Division by zero for 0 quantity items
472
+
473
+ = 1.4.1 =
474
+ * Translations: Added Polish (Thanks Mike!)
475
+ * Fix: Invoice number formatting notices in debug mode
476
+
477
+ = 1.4.0 =
478
+ * Feature: Invoice numbers can now be given a prefix, suffix or padding on the settings page!
479
+ * Filter: `wpo_wcpdf_email_allowed_statuses` to attach pdf to custom order status emails
480
+ * Tweak: Sequential Order Numbers Pro compatibility
481
+ * Tweak: Filenames are now automatically sanitized to prevent issues with illegal characters
482
+
483
+ = 1.3.2 =
484
+ * Fix: error on wpo_wcpdf_email_attachment filter when $pdf_path not set
485
+
486
+ = 1.3.1 =
487
+ * Fix: invoice number was cleared when Order Actions were being used when an invoice number was not set
488
+ * Translations: Updated Slovak (Thanks Jozef!)
489
+ * Translations: Added Czech (Thanks CubiQ!)
490
+
491
+ = 1.3.0 =
492
+ * Feature: Added 'status' panel for better problem diagnosis
493
+ * Tweak: split create & get invoice number calls to prevent slow database calls from causing number skipping
494
+ * Translations: Added Romanian (Thanks Leonardo!)
495
+ * Translations: Added Slovak (Thanks Oleg!)
496
+
497
+ = 1.2.13 =
498
+ * Feature: added filter for custom email attachment condition (wpo_wcpdf_custom_email_condition)
499
+ * Fix: warning for tax implode
500
+
501
+ = 1.2.12 =
502
+ * Fix: hyperlink underline (was more like a strikethrough)
503
+
504
+ = 1.2.11 =
505
+ * Translations: Fixed German spelling error
506
+ * Translations: Updated Swedish (Thanks Fredrik!)
507
+
508
+ = 1.2.10 =
509
+ * Translations: Added Swedish (Thanks Jonathan!)
510
+ * Fix: Line-height issue (on some systems, the space between lines was very high)
511
+
512
+ = 1.2.9 =
513
+ * Fix: bug where 'standard' tax class would not display in some cases
514
+ * Fix: bug that caused the totals to jump for some font sizes
515
+ * Fix: WC2.1 deprecated totals function
516
+ * Fix: If multiple taxes were set up with the same name, only one would display (Simple template was not affected)
517
+
518
+ = 1.2.8 =
519
+ * Template: Body line-height defined to prevent character jumping with italic texts
520
+ * Fix: Open Sans now included in plugin package (fixes font issues for servers with allow_url_fopen disabled)
521
+
522
+ = 1.2.7 =
523
+ * Translations: POT, DE & NL updated
524
+ * Fix: Removed stray span tag in totals table
525
+
526
+ = 1.2.6 =
527
+ * Translations: Spanish update (thanks prepu!)
528
+ * Fix: More advanced checks to determine if a customer can download the invoice (including a status filter)
529
+
530
+ = 1.2.5 =
531
+ * Feature: Optional Invoice Number column for the orders listing
532
+ * Feature: Better support for international characters
533
+ * Translations: Added Russian & Ukrainian translation (thanks Oleg!)
534
+ * Translations: Updated Spanish (Thanks Manuel!) and Dutch translations & POT file
535
+ * Tweak: Memory limit notice
536
+ * Tweak: Filename name now includes invoice number (when configured in the settings)
537
+
538
+ = 1.2.4 =
539
+ * Feature: Set which type of emails you want to attach the invoice to
540
+
541
+ = 1.2.3 =
542
+ * Feature: Manually edit invoice number on the edit order screen
543
+ * Feature: Set the first (/next) invoice number on the settings screen
544
+ * Fix: Bug where invoice number would be generated twice due to slow database calls
545
+ * Fix: php strict warnings
546
+
547
+ = 1.2.2 =
548
+ * Feature: Simple template now uses Open Sans to include more international special characters
549
+ * Feature: Implemented filters for paper size & orientation ([read here](http://wordpress.org/support/topic/select-a5-paper-size-for-packing-slips?replies=5#post-5211129))
550
+ * Tweak: PDF engine updated (dompdf 0.6.0)
551
+ * Tweak: Download PDF link on the my account page is now only shown when an invoice is already created by the admin or automatically, to prevent unwanted invoice created (creating problems with european laws).
552
+
553
+ = 1.2.1 =
554
+ * Fix: shipping & fees functions didn't output correctly with the tax set to 'incl'
555
+
556
+ = 1.2.0 =
557
+ * Feature: Sequential invoice numbers (set upon invoice creation).
558
+ * Feature: Invoice date (set upon invoice creation).
559
+
560
+ = 1.1.6 =
561
+ * Feature: Hungarian translations added - thanks Joseph!
562
+ * Tweak: Better debug code.
563
+ * Tweak: Error reporting when templates not found.
564
+ * Fix: tax rate calculation for free items.
565
+
566
+ = 1.1.5 =
567
+ * Feature: German translations added - thanks Christian!
568
+ * Fix: dompdf 0.6.0 proved to be less stable, so switching back to beta3 for now.
569
+
570
+ = 1.1.4 =
571
+ * Fix: Template paths on windows servers were not properly saved (stripslashes), resulting in an empty output.
572
+
573
+ = 1.1.3 =
574
+ * Feature: PDF engine (dompdf) updated to 0.6.0 for better stability and utf-8 support.
575
+ * Tweak: Local server path is used for header image for better compatibility with server settings.
576
+ * Fix: several small bugs.
577
+
578
+ = 1.1.2 =
579
+ * Feature: Totals can now be called with simpler template functions
580
+ * Feature: Italian translations - thanks max66max!
581
+ * Tweak: improved memory performance
582
+
583
+ = 1.1.1 =
584
+ * Feature: French translations - thanks Guillaume!
585
+
586
+ = 1.1.0 =
587
+ * Feature: Fees can now also be called ex. VAT
588
+ * Feature: Invoices can now be downloaded from the My Account page
589
+ * Feature: Spanish translation & POT file included
590
+ * Fix: ternary statements that caused an error
591
+
592
+ = 1.0.1 =
593
+ * Tweak: Packing slip now displays shipping address instead of billing address
594
+ * Tweak: Variation data is now displayed by default
595
+
596
+ = 1.0.0 =
597
+ * First release
598
+
599
+ == Upgrade Notice ==
600
+
601
+ = 1.5 =
602
+ Version 1.5 changes where temporary files are stored - everything is now stored centrally in the WP uploads folder. For backwards compatibility, this feature is turned off by default, but we recommend to use the new folders. Check the plugin Status panel for more information!
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -1,978 +1,982 @@
1
- <?php
2
- /**
3
- * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
- * Plugin URI: http://www.wpovernight.com
5
- * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 1.5.28
7
- * Author: Ewout Fernhout
8
- * Author URI: http://www.wpovernight.com
9
- * License: GPLv2 or later
10
- * License URI: http://www.opensource.org/licenses/gpl-license.php
11
- * Text Domain: wpo_wcpdf
12
- */
13
-
14
- if ( !class_exists( 'WooCommerce_PDF_Invoices' ) ) {
15
-
16
- class WooCommerce_PDF_Invoices {
17
-
18
- public static $plugin_prefix;
19
- public static $plugin_url;
20
- public static $plugin_path;
21
- public static $plugin_basename;
22
- public static $version;
23
-
24
- public $writepanels;
25
- public $settings;
26
- public $export;
27
-
28
- /**
29
- * Constructor
30
- */
31
- public function __construct() {
32
- self::$plugin_prefix = 'wpo_wcpdf_';
33
- self::$plugin_basename = plugin_basename(__FILE__);
34
- self::$plugin_url = plugin_dir_url(self::$plugin_basename);
35
- self::$plugin_path = trailingslashit(dirname(__FILE__));
36
- self::$version = '1.5.28';
37
-
38
- // load the localisation & classes
39
- add_action( 'plugins_loaded', array( $this, 'translations' ) ); // or use init?
40
- add_action( 'init', array( $this, 'load_classes' ) );
41
-
42
- // run lifecycle methods
43
- if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
44
- // check if upgrading from versionless (1.4.14 and older)
45
- if ( get_option('wpo_wcpdf_general_settings') && get_option('wpo_wcpdf_version') === false ) {
46
- // tag 'versionless', so that we can apply necessary upgrade settings
47
- add_option( 'wpo_wcpdf_version', 'versionless' );
48
- }
49
-
50
- add_action( 'wp_loaded', array( $this, 'do_install' ) );
51
- }
52
- }
53
-
54
- /**
55
- * Load the translation / textdomain files
56
- *
57
- * Note: the first-loaded translation file overrides any following ones if the same translation is present
58
- */
59
- public function translations() {
60
- $locale = apply_filters( 'plugin_locale', get_locale(), 'wpo_wcpdf' );
61
- $dir = trailingslashit( WP_LANG_DIR );
62
-
63
- /**
64
- * Frontend/global Locale. Looks in:
65
- *
66
- * - WP_LANG_DIR/woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-LOCALE.mo
67
- * - WP_LANG_DIR/plugins/wpo_wcpdf-LOCALE.mo
68
- * - woocommerce-pdf-invoices-packing-slips/languages/wpo_wcpdf-LOCALE.mo (which if not found falls back to:)
69
- * - WP_LANG_DIR/plugins/wpo_wcpdf-LOCALE.mo
70
- */
71
- load_textdomain( 'wpo_wcpdf', $dir . 'woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-' . $locale . '.mo' );
72
- load_textdomain( 'wpo_wcpdf', $dir . 'plugins/wpo_wcpdf-' . $locale . '.mo' );
73
- load_plugin_textdomain( 'wpo_wcpdf', false, dirname( self::$plugin_basename ) . '/languages' );
74
- }
75
-
76
- /**
77
- * Load the main plugin classes and functions
78
- */
79
- public function includes() {
80
- include_once( 'includes/class-wcpdf-settings.php' );
81
- include_once( 'includes/class-wcpdf-writepanels.php' );
82
- include_once( 'includes/class-wcpdf-export.php' );
83
- }
84
-
85
-
86
- /**
87
- * Instantiate classes when woocommerce is activated
88
- */
89
- public function load_classes() {
90
- if ( $this->is_woocommerce_activated() ) {
91
- $this->includes();
92
- $this->settings = new WooCommerce_PDF_Invoices_Settings();
93
- $this->writepanels = new WooCommerce_PDF_Invoices_Writepanels();
94
- $this->export = new WooCommerce_PDF_Invoices_Export();
95
- } else {
96
- // display notice instead
97
- add_action( 'admin_notices', array ( $this, 'need_woocommerce' ) );
98
- }
99
-
100
- }
101
-
102
- /**
103
- * Check if woocommerce is activated
104
- */
105
- public function is_woocommerce_activated() {
106
- $blog_plugins = get_option( 'active_plugins', array() );
107
- $site_plugins = get_site_option( 'active_sitewide_plugins', array() );
108
-
109
- if ( in_array( 'woocommerce/woocommerce.php', $blog_plugins ) || isset( $site_plugins['woocommerce/woocommerce.php'] ) ) {
110
- return true;
111
- } else {
112
- return false;
113
- }
114
- }
115
-
116
- /**
117
- * WooCommerce not active notice.
118
- *
119
- * @return string Fallack notice.
120
- */
121
-
122
- public function need_woocommerce() {
123
- $error = sprintf( __( 'WooCommerce PDF Invoices & Packing Slips requires %sWooCommerce%s to be installed & activated!' , 'wpo_wcpdf' ), '<a href="http://wordpress.org/extend/plugins/woocommerce/">', '</a>' );
124
-
125
- $message = '<div class="error"><p>' . $error . '</p></div>';
126
-
127
- echo $message;
128
- }
129
-
130
- /** Lifecycle methods *******************************************************
131
- * Because register_activation_hook only runs when the plugin is manually
132
- * activated by the user, we're checking the current version against the
133
- * version stored in the database
134
- ****************************************************************************/
135
-
136
- /**
137
- * Handles version checking
138
- */
139
- public function do_install() {
140
- // only install when woocommerce is active
141
- if ( !$this->is_woocommerce_activated() ) {
142
- return;
143
- }
144
-
145
- $version_setting = 'wpo_wcpdf_version';
146
- $installed_version = get_option( $version_setting );
147
-
148
- // installed version lower than plugin version?
149
- if ( version_compare( $installed_version, self::$version, '<' ) ) {
150
-
151
- if ( ! $installed_version ) {
152
- $this->install();
153
- } else {
154
- $this->upgrade( $installed_version );
155
- }
156
-
157
- // new version number
158
- update_option( $version_setting, self::$version );
159
- }
160
- }
161
-
162
-
163
- /**
164
- * Plugin install method. Perform any installation tasks here
165
- */
166
- protected function install() {
167
- // Create temp folders
168
- $tmp_base = $this->export->get_tmp_base();
169
-
170
- // check if tmp folder exists => if not, initialize
171
- if ( !@is_dir( $tmp_base ) ) {
172
- $this->export->init_tmp( $tmp_base );
173
- }
174
-
175
- }
176
-
177
-
178
- /**
179
- * Plugin upgrade method. Perform any required upgrades here
180
- *
181
- * @param string $installed_version the currently installed version
182
- */
183
- protected function upgrade( $installed_version ) {
184
- if ( $installed_version == 'versionless') { // versionless = 1.4.14 and older
185
- // We're upgrading from an old version, so we're enabling the option to use the plugin tmp folder.
186
- // This is not per se the 'best' solution, but the good thing is that nothing is changed
187
- // and nothing will be broken (that wasn't broken before)
188
- $default = array( 'old_tmp' => 1 );
189
- update_option( 'wpo_wcpdf_debug_settings', $default );
190
- }
191
-
192
- // sync fonts on every upgrade!
193
- $debug_settings = get_option( 'wpo_wcpdf_debug_settings' ); // get temp setting
194
-
195
- // do not copy if old_tmp function active! (double check for slow databases)
196
- if ( !( isset($this->debug_settings['old_tmp']) || $installed_version == 'versionless' ) ) {
197
- $tmp_base = $this->export->get_tmp_base();
198
-
199
- // check if tmp folder exists => if not, initialize
200
- if ( !@is_dir( $tmp_base ) ) {
201
- $this->export->init_tmp( $tmp_base );
202
- }
203
-
204
- $font_path = $tmp_base . 'fonts/';
205
- $this->export->copy_fonts( $font_path );
206
- }
207
-
208
- // 1.5.28 update: copy next invoice number to separate setting
209
- if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
210
- $template_settings = get_option( 'wpo_wcpdf_template_settings' );
211
- $next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
212
- update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
213
- }
214
- }
215
-
216
- /***********************************************************************/
217
- /********************** GENERAL TEMPLATE FUNCTIONS *********************/
218
- /***********************************************************************/
219
-
220
- /**
221
- * Get template name from slug
222
- */
223
- public function get_template_name ( $template_type ) {
224
- switch ( $template_type ) {
225
- case 'invoice':
226
- $template_name = apply_filters( 'wpo_wcpdf_invoice_title', __( 'Invoice', 'wpo_wcpdf' ) );
227
- break;
228
- case 'packing-slip':
229
- $template_name = apply_filters( 'wpo_wcpdf_packing_slip_title', __( 'Packing Slip', 'wpo_wcpdf' ) );
230
- break;
231
- default:
232
- // try to 'unslug' the name
233
- $template_name = ucwords( str_replace( array( '_', '-' ), ' ', $template_type ) );
234
- break;
235
- }
236
-
237
- return apply_filters( 'wpo_wcpdf_template_name', $template_name, $template_type );
238
- }
239
-
240
- /**
241
- * Output template styles
242
- */
243
- public function template_styles() {
244
- $css = apply_filters( 'wpo_wcpdf_template_styles_file', $this->export->template_path. '/' .'style.css' );
245
-
246
- ob_start();
247
- if (file_exists($css)) {
248
- include($css);
249
- }
250
- $html = ob_get_clean();
251
- $html = apply_filters( 'wpo_wcpdf_template_styles', $html );
252
-
253
- echo $html;
254
- }
255
-
256
- /**
257
- * Return logo id
258
- */
259
- public function get_header_logo_id() {
260
- if (isset($this->settings->template_settings['header_logo'])) {
261
- return apply_filters( 'wpo_wcpdf_header_logo_id', $this->settings->template_settings['header_logo'] );
262
- }
263
- }
264
-
265
- /**
266
- * Show logo html
267
- */
268
- public function header_logo() {
269
- if ($this->get_header_logo_id()) {
270
- $attachment_id = $this->get_header_logo_id();
271
- $company = isset($this->settings->template_settings['shop_name'])? $this->settings->template_settings['shop_name'] : '';
272
- if( $attachment_id ) {
273
- $attachment = wp_get_attachment_image_src( $attachment_id, 'full', false );
274
-
275
- $attachment_src = $attachment[0];
276
- $attachment_width = $attachment[1];
277
- $attachment_height = $attachment[2];
278
-
279
- $attachment_path = get_attached_file( $attachment_id );
280
-
281
- if ( apply_filters('wpo_wcpdf_use_path', true) && file_exists($attachment_path) ) {
282
- $src = $attachment_path;
283
- } else {
284
- $src = $attachment_src;
285
- }
286
-
287
- printf('<img src="%1$s" width="%2$d" height="%3$d" alt="%4$s" />', $src, $attachment_width, $attachment_height, esc_attr( $company ) );
288
- }
289
- }
290
- }
291
-
292
- /**
293
- * Return/Show custom company name or default to blog name
294
- */
295
- public function get_shop_name() {
296
- if (!empty($this->settings->template_settings['shop_name'])) {
297
- $name = trim( $this->settings->template_settings['shop_name'] );
298
- return apply_filters( 'wpo_wcpdf_shop_name', wptexturize( $name ) );
299
- } else {
300
- return apply_filters( 'wpo_wcpdf_shop_name', get_bloginfo( 'name' ) );
301
- }
302
- }
303
- public function shop_name() {
304
- echo $this->get_shop_name();
305
- }
306
-
307
- /**
308
- * Return/Show shop/company address if provided
309
- */
310
- public function get_shop_address() {
311
- if (isset($this->settings->template_settings['shop_address']))
312
- return apply_filters( 'wpo_wcpdf_shop_address', wpautop( wptexturize( $this->settings->template_settings['shop_address'] ) ) );
313
- }
314
- public function shop_address() {
315
- echo $this->get_shop_address();
316
- }
317
-
318
- /**
319
- * Check if billing address and shipping address are equal
320
- */
321
- public function ships_to_different_address() {
322
- // always prefer parent address for refunds
323
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
324
- // temporarily switch order to make all filters / order calls work correctly
325
- $order_meta = get_post_meta( $parent_order_id );
326
- } else {
327
- $order_meta = get_post_meta( $this->export->order->id );
328
- }
329
-
330
- $address_comparison_fields = apply_filters( 'wpo_wcpdf_address_comparison_fields', array(
331
- 'first_name',
332
- 'last_name',
333
- 'company',
334
- 'address_1',
335
- 'address_2',
336
- 'city',
337
- 'state',
338
- 'postcode',
339
- 'country'
340
- ) );
341
-
342
- foreach ($address_comparison_fields as $address_field) {
343
- $billing_field = isset( $order_meta['_billing_'.$address_field] ) ? $order_meta['_billing_'.$address_field] : '';
344
- $shipping_field = isset( $order_meta['_shipping_'.$address_field] ) ? $order_meta['_shipping_'.$address_field] : '';
345
- if ( $shipping_field != $billing_field ) {
346
- // this address field is different -> ships to different address!
347
- return true;
348
- }
349
- }
350
-
351
- //if we got here, it means the addresses are equal -> doesn't ship to different address!
352
- return apply_filters( 'wpo_wcpdf_ships_to_different_address', false, $order_meta );
353
- }
354
-
355
- /**
356
- * Return/Show billing address
357
- */
358
- public function get_billing_address() {
359
- // always prefer parent billing address for refunds
360
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
361
- // temporarily switch order to make all filters / order calls work correctly
362
- $current_order = $this->export->order;
363
- $this->export->order = new WC_Order( $parent_order_id );
364
- $address = apply_filters( 'wpo_wcpdf_billing_address', $this->export->order->get_formatted_billing_address() );
365
- // switch back & unset
366
- $this->export->order = $current_order;
367
- unset($current_order);
368
- } elseif ( $address = $this->export->order->get_formatted_billing_address() ) {
369
- // regular shop_order
370
- $address = apply_filters( 'wpo_wcpdf_billing_address', $address );
371
- } else {
372
- // no address
373
- $address = apply_filters( 'wpo_wcpdf_billing_address', __('N/A', 'wpo_wcpdf') );
374
- }
375
-
376
- return $address;
377
- }
378
- public function billing_address() {
379
- echo $this->get_billing_address();
380
- }
381
-
382
- /**
383
- * Return/Show billing email
384
- */
385
- public function get_billing_email() {
386
- $billing_email = $this->export->order->billing_email;
387
-
388
- if ( !$billing_email && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
389
- // try parent
390
- $billing_email = get_post_meta( $parent_order_id, '_billing_email', true );
391
- }
392
-
393
- return apply_filters( 'wpo_wcpdf_billing_email', $billing_email );
394
- }
395
- public function billing_email() {
396
- echo $this->get_billing_email();
397
- }
398
-
399
- /**
400
- * Return/Show billing phone
401
- */
402
- public function get_billing_phone() {
403
- $billing_phone = $this->export->order->billing_phone;
404
-
405
- if ( !$billing_phone && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
406
- // try parent
407
- $billing_phone = get_post_meta( $parent_order_id, '_billing_phone', true );
408
- }
409
-
410
- return apply_filters( 'wpo_wcpdf_billing_phone', $billing_phone );
411
- }
412
- public function billing_phone() {
413
- echo $this->get_billing_phone();
414
- }
415
-
416
- /**
417
- * Return/Show shipping address
418
- */
419
- public function get_shipping_address() {
420
- // always prefer parent shipping address for refunds
421
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
422
- // temporarily switch order to make all filters / order calls work correctly
423
- $current_order = $this->export->order;
424
- $this->export->order = new WC_Order( $parent_order_id );
425
- $address = apply_filters( 'wpo_wcpdf_shipping_address', $this->export->order->get_formatted_shipping_address() );
426
- // switch back & unset
427
- $this->export->order = $current_order;
428
- unset($current_order);
429
- } elseif ( $address = $this->export->order->get_formatted_shipping_address() ) {
430
- // regular shop_order
431
- $address = apply_filters( 'wpo_wcpdf_shipping_address', $address );
432
- } else {
433
- // no address
434
- $address = apply_filters( 'wpo_wcpdf_shipping_address', __('N/A', 'wpo_wcpdf') );
435
- }
436
-
437
- return $address;
438
- }
439
- public function shipping_address() {
440
- echo $this->get_shipping_address();
441
- }
442
-
443
- /**
444
- * Return/Show a custom field
445
- */
446
- public function get_custom_field( $field_name ) {
447
- $custom_field = get_post_meta($this->export->order->id,$field_name,true);
448
-
449
- if ( !$custom_field && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
450
- // try parent
451
- $custom_field = get_post_meta( $parent_order_id, $field_name, true );
452
- }
453
-
454
- return apply_filters( 'wpo_wcpdf_billing_custom_field', $custom_field );
455
- }
456
- public function custom_field( $field_name, $field_label = '', $display_empty = false ) {
457
- $custom_field = $this->get_custom_field( $field_name );
458
- if (!empty($field_label)){
459
- // add a a trailing space to the label
460
- $field_label .= ' ';
461
- }
462
-
463
- if (!empty($custom_field) || $display_empty) {
464
- echo $field_label . nl2br ($custom_field);
465
- }
466
- }
467
-
468
- /**
469
- * Return/Show order notes
470
- */
471
- public function get_order_notes( $filter = 'customer' ) {
472
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
473
- $post_id = $parent_order_id;
474
- } else {
475
- $post_id = $this->export->order->id;
476
- }
477
-
478
- $args = array(
479
- 'post_id' => $post_id,
480
- 'approve' => 'approve',
481
- 'type' => 'order_note'
482
- );
483
-
484
- remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
485
-
486
- $notes = get_comments( $args );
487
-
488
- add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
489
-
490
- if ( $notes ) {
491
- foreach( $notes as $key => $note ) {
492
- if ( $filter == 'customer' && !get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ) {
493
- unset($notes[$key]);
494
- }
495
- if ( $filter == 'private' && get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ) {
496
- unset($notes[$key]);
497
- }
498
- }
499
- return $notes;
500
- }
501
- }
502
- public function order_notes( $filter = 'customer' ) {
503
- $notes = $this->get_order_notes( $filter );
504
- if ( $notes ) {
505
- foreach( $notes as $note ) {
506
- ?>
507
- <div class="note_content">
508
- <?php echo wpautop( wptexturize( wp_kses_post( $note->comment_content ) ) ); ?>
509
- </div>
510
- <?php
511
- }
512
- }
513
- }
514
-
515
- /**
516
- * Return/Show the current date
517
- */
518
- public function get_current_date() {
519
- return apply_filters( 'wpo_wcpdf_date', date_i18n( get_option( 'date_format' ) ) );
520
- }
521
- public function current_date() {
522
- echo $this->get_current_date();
523
- }
524
-
525
- /**
526
- * Return/Show payment method
527
- */
528
- public function get_payment_method() {
529
- $payment_method_label = __( 'Payment method', 'wpo_wcpdf' );
530
-
531
- $payment_method = __( $this->export->order->payment_method_title, 'woocommerce' );
532
- if ( !$payment_method && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
533
- // try parent
534
- $payment_method = get_post_meta( $parent_order_id, '_payment_method_title', true );
535
- $payment_method = __( $payment_method, 'woocommerce' );
536
- }
537
-
538
- return apply_filters( 'wpo_wcpdf_payment_method', $payment_method );
539
- }
540
- public function payment_method() {
541
- echo $this->get_payment_method();
542
- }
543
-
544
- /**
545
- * Return/Show shipping method
546
- */
547
- public function get_shipping_method() {
548
- $shipping_method_label = __( 'Shipping method', 'wpo_wcpdf' );
549
- return apply_filters( 'wpo_wcpdf_shipping_method', __( $this->export->order->get_shipping_method(), 'woocommerce' ) );
550
- }
551
- public function shipping_method() {
552
- echo $this->get_shipping_method();
553
- }
554
-
555
- /**
556
- * Return/Show order number
557
- */
558
- public function get_order_number() {
559
- // try parent first
560
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
561
- $parent_order = new WC_Order( $parent_order_id );
562
- $order_number = $parent_order->get_order_number();
563
- } else {
564
- $order_number = $this->export->order->get_order_number();
565
- }
566
-
567
- // Trim the hash to have a clean number but still
568
- // support any filters that were applied before.
569
- $order_number = ltrim($order_number, '#');
570
- return apply_filters( 'wpo_wcpdf_order_number', $order_number);
571
- }
572
- public function order_number() {
573
- echo $this->get_order_number();
574
- }
575
-
576
- /**
577
- * Return/Show invoice number
578
- */
579
- public function get_invoice_number() {
580
- // try parent first
581
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
582
- $invoice_number = $this->export->get_invoice_number( $parent_order_id );
583
- } else {
584
- $invoice_number = $this->export->get_invoice_number( $this->export->order->id );
585
- }
586
-
587
- return $invoice_number;
588
- }
589
- public function invoice_number() {
590
- echo $this->get_invoice_number();
591
- }
592
-
593
- /**
594
- * Return/Show the order date
595
- */
596
- public function get_order_date() {
597
- if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
598
- $parent_order = new WC_Order( $parent_order_id );
599
- $order_date = $parent_order->order_date;
600
- } else {
601
- $order_date = $this->export->order->order_date;
602
- }
603
-
604
- $date = date_i18n( get_option( 'date_format' ), strtotime( $order_date ) );
605
- return apply_filters( 'wpo_wcpdf_order_date', $date, $order_date );
606
- }
607
- public function order_date() {
608
- echo $this->get_order_date();
609
- }
610
-
611
- /**
612
- * Return/Show the invoice date
613
- */
614
- public function get_invoice_date() {
615
- $invoice_date = get_post_meta($this->export->order->id,'_wcpdf_invoice_date',true);
616
-
617
- // add invoice date if it doesn't exist
618
- if ( empty($invoice_date) || !isset($invoice_date) ) {
619
- $invoice_date = current_time('mysql');
620
- update_post_meta( $this->export->order->id, '_wcpdf_invoice_date', $invoice_date );
621
- }
622
-
623
- $formatted_invoice_date = date_i18n( get_option( 'date_format' ), strtotime( $invoice_date ) );
624
-
625
- return apply_filters( 'wpo_wcpdf_invoice_date', $formatted_invoice_date, $invoice_date );
626
- }
627
- public function invoice_date() {
628
- echo $this->get_invoice_date();
629
- }
630
-
631
- /**
632
- * Return the order items
633
- */
634
- public function get_order_items() {
635
- return apply_filters( 'wpo_wcpdf_order_items', $this->export->get_order_items() );
636
- }
637
-
638
- /**
639
- * Return/show product attribute
640
- */
641
- public function get_product_attribute( $attribute_name, $product ) {
642
- // first, check the text attributes
643
- $attributes = $product->get_attributes();
644
- $attribute_key = @wc_attribute_taxonomy_name( $attribute_name );
645
- if (array_key_exists( sanitize_title( $attribute_name ), $attributes) ) {
646
- $attribute = $product->get_attribute ( $attribute_name );
647
- return $attribute;
648
- } elseif (array_key_exists( sanitize_title( $attribute_key ), $attributes) ) {
649
- $attribute = $product->get_attribute ( $attribute_key );
650
- return $attribute;
651
- }
652
-
653
- // not a text attribute, try attribute taxonomy
654
- $attribute_key = @wc_attribute_taxonomy_name( $attribute_name );
655
- $product_terms = @wc_get_product_terms( $product->id, $attribute_key, array( 'fields' => 'names' ) );
656
- // check if not empty, then display
657
- if ( !empty($product_terms) ) {
658
- $attribute = array_shift( $product_terms );
659
- return $attribute;
660
- } else {
661
- // no attribute under this name
662
- return false;
663
- }
664
- }
665
- public function product_attribute( $attribute_name, $product ) {
666
- echo $this->get_product_attribute( $attribute_name, $product );
667
- }
668
-
669
-
670
- /**
671
- * Return the order totals listing
672
- */
673
- public function get_woocommerce_totals() {
674
- // get totals and remove the semicolon
675
- $totals = apply_filters( 'wpo_wcpdf_raw_order_totals', $this->export->order->get_order_item_totals(), $this->export->order );
676
-
677
- // remove the colon for every label
678
- foreach ( $totals as $key => $total ) {
679
- $label = $total['label'];
680
- $colon = strrpos( $label, ':' );
681
- if( $colon !== false ) {
682
- $label = substr_replace( $label, '', $colon, 1 );
683
- }
684
- $totals[$key]['label'] = $label;
685
- }
686
-
687
- // WC2.4 fix order_total for refunded orders
688
- if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '>=' ) && isset($totals['order_total']) ) {
689
- $tax_display = $this->export->order->tax_display_cart;
690
- $totals['order_total']['value'] = wc_price( $this->export->order->get_total(), array( 'currency' => $this->export->order->get_order_currency() ) );
691
- $order_total = $this->export->order->get_total();
692
- $tax_string = '';
693
-
694
- // Tax for inclusive prices
695
- if ( wc_tax_enabled() && 'incl' == $tax_display ) {
696
- $tax_string_array = array();
697
-
698
- if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) {
699
- foreach ( $this->export->order->get_tax_totals() as $code => $tax ) {
700
- $tax_amount = $tax->formatted_amount;
701
- $tax_string_array[] = sprintf( '%s %s', $tax_amount, $tax->label );
702
- }
703
- } else {
704
- $tax_string_array[] = sprintf( '%s %s', wc_price( $this->export->order->get_total_tax() - $this->export->order->get_total_tax_refunded(), array( 'currency' => $this->export->order->get_order_currency() ) ), WC()->countries->tax_or_vat() );
705
- }
706
- if ( ! empty( $tax_string_array ) ) {
707
- $tax_string = ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) );
708
- }
709
- }
710
-
711
- $totals['order_total']['value'] .= $tax_string;
712
- }
713
-
714
- return apply_filters( 'wpo_wcpdf_woocommerce_totals', $totals, $this->export->order );
715
- }
716
-
717
- /**
718
- * Return/show the order subtotal
719
- */
720
- public function get_order_subtotal( $tax = 'excl', $discount = 'incl' ) { // set $tax to 'incl' to include tax, same for $discount
721
- //$compound = ($discount == 'incl')?true:false;
722
-
723
- $subtotal = $this->export->order->get_subtotal_to_display( false, $tax );
724
-
725
- $subtotal = ($pos = strpos($subtotal, ' <small>')) ? substr($subtotal, 0, $pos) : $subtotal; //removing the 'excluding tax' text
726
-
727
- $subtotal = array (
728
- 'label' => __('Subtotal', 'wpo_wcpdf'),
729
- 'value' => $subtotal,
730
- );
731
-
732
- return apply_filters( 'wpo_wcpdf_order_subtotal', $subtotal, $tax, $discount );
733
- }
734
- public function order_subtotal( $tax = 'excl', $discount = 'incl' ) {
735
- $subtotal = $this->get_order_subtotal( $tax, $discount );
736
- echo $subtotal['value'];
737
- }
738
-
739
- /**
740
- * Return/show the order shipping costs
741
- */
742
- public function get_order_shipping( $tax = 'excl' ) { // set $tax to 'incl' to include tax
743
- if ($tax == 'excl' ) {
744
- $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping );
745
- } else {
746
- $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping + $this->export->order->order_shipping_tax );
747
- }
748
-
749
- $shipping = array (
750
- 'label' => __('Shipping', 'wpo_wcpdf'),
751
- 'value' => $shipping_costs,
752
- 'tax' => $this->export->wc_price( $this->export->order->order_shipping_tax ),
753
- );
754
- return apply_filters( 'wpo_wcpdf_order_shipping', $shipping, $tax );
755
- }
756
- public function order_shipping( $tax = 'excl' ) {
757
- $shipping = $this->get_order_shipping( $tax );
758
- echo $shipping['value'];
759
- }
760
-
761
- /**
762
- * Return/show the total discount
763
- */
764
- public function get_order_discount( $type = 'total', $tax = 'incl' ) {
765
- if ( $tax == 'incl' ) {
766
- switch ($type) {
767
- case 'cart':
768
- // Cart Discount - pre-tax discounts. (deprecated in WC2.3)
769
- $discount_value = $this->export->order->get_cart_discount();
770
- break;
771
- case 'order':
772
- // Order Discount - post-tax discounts. (deprecated in WC2.3)
773
- $discount_value = $this->export->order->get_order_discount();
774
- break;
775
- case 'total':
776
- // Total Discount
777
- if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
778
- $discount_value = $this->export->order->get_total_discount( false ); // $ex_tax = false
779
- } else {
780
- // WC2.2 and older: recalculate to include tax
781
- $discount_value = 0;
782
- $items = $this->export->order->get_items();;
783
- if( sizeof( $items ) > 0 ) {
784
- foreach( $items as $item ) {
785
- $discount_value += ($item['line_subtotal'] + $item['line_subtotal_tax']) - ($item['line_total'] + $item['line_tax']);
786
- }
787
- }
788
- }
789
-
790
- break;
791
- default:
792
- // Total Discount - Cart & Order Discounts combined
793
- $discount_value = $this->export->order->get_total_discount();
794
- break;
795
- }
796
- } else { // calculate discount excluding tax
797
- if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
798
- $discount_value = $this->export->order->get_total_discount( true ); // $ex_tax = true
799
- } else {
800
- // WC2.2 and older: recalculate to exclude tax
801
- $discount_value = 0;
802
-
803
- $items = $this->export->order->get_items();;
804
- if( sizeof( $items ) > 0 ) {
805
- foreach( $items as $item ) {
806
- $discount_value += ($item['line_subtotal'] - $item['line_total']);
807
- }
808
- }
809
- }
810
- }
811
-
812
- $discount = array (
813
- 'label' => __('Discount', 'wpo_wcpdf'),
814
- 'value' => $this->export->wc_price($discount_value),
815
- 'raw_value' => $discount_value,
816
- );
817
-
818
- if ( round( $discount_value, 3 ) != 0 ) {
819
- return apply_filters( 'wpo_wcpdf_order_discount', $discount, $type, $tax );
820
- }
821
- }
822
- public function order_discount( $type = 'total', $tax = 'incl' ) {
823
- $discount = $this->get_order_discount( $type, $tax );
824
- echo $discount['value'];
825
- }
826
-
827
- /**
828
- * Return the order fees
829
- */
830
- public function get_order_fees( $tax = 'excl' ) {
831
- if ( $wcfees = $this->export->order->get_fees() ) {
832
- foreach( $wcfees as $id => $fee ) {
833
- if ($tax == 'excl' ) {
834
- $fee_price = $this->export->wc_price( $fee['line_total'] );
835
- } else {
836
- $fee_price = $this->export->wc_price( $fee['line_total'] + $fee['line_tax'] );
837
- }
838
-
839
- $fees[ $id ] = array(
840
- 'label' => $fee['name'],
841
- 'value' => $fee_price,
842
- 'line_total' => $this->export->wc_price($fee['line_total']),
843
- 'line_tax' => $this->export->wc_price($fee['line_tax'])
844
- );
845
- }
846
- return $fees;
847
- }
848
- }
849
-
850
- /**
851
- * Return the order taxes
852
- */
853
- public function get_order_taxes() {
854
- $tax_label = __( 'VAT', 'wpo_wcpdf' ); // register alternate label translation
855
- $tax_label = __( 'Tax rate', 'wpo_wcpdf' );
856
- $tax_rate_ids = $this->export->get_tax_rate_ids();
857
- if ($this->export->order->get_taxes()) {
858
- foreach ( $this->export->order->get_taxes() as $key => $tax ) {
859
- $taxes[ $key ] = array(
860
- 'label' => isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ],
861
- 'value' => $this->export->wc_price( ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] ) ),
862
- 'rate_id' => $tax['rate_id'],
863
- 'tax_amount' => $tax['tax_amount'],
864
- 'shipping_tax_amount' => $tax['shipping_tax_amount'],
865
- 'rate' => isset( $tax_rate_ids[ $tax['rate_id'] ] ) ? ( (float) $tax_rate_ids[$tax['rate_id']]['tax_rate'] ) . ' %': '',
866
- );
867
- }
868
-
869
- return apply_filters( 'wpo_wcpdf_order_taxes', $taxes );
870
- }
871
- }
872
-
873
- /**
874
- * Return/show the order grand total
875
- */
876
- public function get_order_grand_total( $tax = 'incl' ) {
877
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
878
- // WC 2.1 or newer is used
879
- $total_unformatted = $this->export->order->get_total();
880
- } else {
881
- // Backwards compatibility
882
- $total_unformatted = $this->export->order->get_order_total();
883
- }
884
-
885
- if ($tax == 'excl' ) {
886
- $total_tax = 0;
887
- foreach ( $this->export->order->get_taxes() as $tax ) {
888
- $total_tax += ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] );
889
- }
890
-
891
- $total = $this->export->wc_price( ( $total_unformatted - $total_tax ) );
892
- $label = __( 'Total ex. VAT', 'wpo_wcpdf' );
893
- } else {
894
- $total = $this->export->wc_price( ( $total_unformatted ) );
895
- $label = __( 'Total', 'wpo_wcpdf' );
896
- }
897
-
898
- $grand_total = array(
899
- 'label' => $label,
900
- 'value' => $total,
901
- );
902
-
903
- return apply_filters( 'wpo_wcpdf_order_grand_total', $grand_total, $tax );
904
- }
905
- public function order_grand_total( $tax = 'incl' ) {
906
- $grand_total = $this->get_order_grand_total( $tax );
907
- echo $grand_total['value'];
908
- }
909
-
910
-
911
- /**
912
- * Return/Show shipping notes
913
- */
914
- public function get_shipping_notes() {
915
- $shipping_notes = wpautop( wptexturize( $this->export->order->customer_note ) );
916
- return apply_filters( 'wpo_wcpdf_shipping_notes', $shipping_notes );
917
- }
918
- public function shipping_notes() {
919
- echo $this->get_shipping_notes();
920
- }
921
-
922
-
923
- /**
924
- * Return/Show shop/company footer imprint, copyright etc.
925
- */
926
- public function get_footer() {
927
- if (isset($this->settings->template_settings['footer'])) {
928
- $footer = wpautop( wptexturize( $this->settings->template_settings[ 'footer' ] ) );
929
- return apply_filters( 'wpo_wcpdf_footer', $footer );
930
- }
931
- }
932
- public function footer() {
933
- echo $this->get_footer();
934
- }
935
-
936
- /**
937
- * Return/Show Extra field 1
938
- */
939
- public function get_extra_1() {
940
- if (isset($this->settings->template_settings['extra_1'])) {
941
- $extra_1 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_1' ] ) );
942
- return apply_filters( 'wpo_wcpdf_extra_1', $extra_1 );
943
- }
944
- }
945
- public function extra_1() {
946
- echo $this->get_extra_1();
947
- }
948
-
949
- /**
950
- * Return/Show Extra field 2
951
- */
952
- public function get_extra_2() {
953
- if (isset($this->settings->template_settings['extra_2'])) {
954
- $extra_2 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_2' ] ) );
955
- return apply_filters( 'wpo_wcpdf_extra_2', $extra_2 );
956
- }
957
- }
958
- public function extra_2() {
959
- echo $this->get_extra_2();
960
- }
961
-
962
- /**
963
- * Return/Show Extra field 3
964
- */
965
- public function get_extra_3() {
966
- if (isset($this->settings->template_settings['extra_3'])) {
967
- $extra_3 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_3' ] ) );
968
- return apply_filters( 'wpo_wcpdf_extra_3', $extra_3 );
969
- }
970
- }
971
- public function extra_3() {
972
- echo $this->get_extra_3();
973
- }
974
- }
975
- }
976
-
977
- // Load main plugin class
978
- $wpo_wcpdf = new WooCommerce_PDF_Invoices();
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
+ * Plugin URI: http://www.wpovernight.com
5
+ * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 1.5.29
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: wpo_wcpdf
12
+ */
13
+
14
+ if ( !class_exists( 'WooCommerce_PDF_Invoices' ) ) {
15
+
16
+ class WooCommerce_PDF_Invoices {
17
+
18
+ public static $plugin_prefix;
19
+ public static $plugin_url;
20
+ public static $plugin_path;
21
+ public static $plugin_basename;
22
+ public static $version;
23
+
24
+ public $writepanels;
25
+ public $settings;
26
+ public $export;
27
+
28
+ /**
29
+ * Constructor
30
+ */
31
+ public function __construct() {
32
+ self::$plugin_prefix = 'wpo_wcpdf_';
33
+ self::$plugin_basename = plugin_basename(__FILE__);
34
+ self::$plugin_url = plugin_dir_url(self::$plugin_basename);
35
+ self::$plugin_path = trailingslashit(dirname(__FILE__));
36
+ self::$version = '1.5.29';
37
+
38
+ // load the localisation & classes
39
+ add_action( 'plugins_loaded', array( $this, 'translations' ) ); // or use init?
40
+ add_action( 'init', array( $this, 'load_classes' ) );
41
+
42
+ // run lifecycle methods
43
+ if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
44
+ // check if upgrading from versionless (1.4.14 and older)
45
+ if ( get_option('wpo_wcpdf_general_settings') && get_option('wpo_wcpdf_version') === false ) {
46
+ // tag 'versionless', so that we can apply necessary upgrade settings
47
+ add_option( 'wpo_wcpdf_version', 'versionless' );
48
+ }
49
+
50
+ add_action( 'wp_loaded', array( $this, 'do_install' ) );
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Load the translation / textdomain files
56
+ *
57
+ * Note: the first-loaded translation file overrides any following ones if the same translation is present
58
+ */
59
+ public function translations() {
60
+ $locale = apply_filters( 'plugin_locale', get_locale(), 'wpo_wcpdf' );
61
+ $dir = trailingslashit( WP_LANG_DIR );
62
+
63
+ /**
64
+ * Frontend/global Locale. Looks in:
65
+ *
66
+ * - WP_LANG_DIR/woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-LOCALE.mo
67
+ * - WP_LANG_DIR/plugins/wpo_wcpdf-LOCALE.mo
68
+ * - woocommerce-pdf-invoices-packing-slips/languages/wpo_wcpdf-LOCALE.mo (which if not found falls back to:)
69
+ * - WP_LANG_DIR/plugins/wpo_wcpdf-LOCALE.mo
70
+ */
71
+ load_textdomain( 'wpo_wcpdf', $dir . 'woocommerce-pdf-invoices-packing-slips/wpo_wcpdf-' . $locale . '.mo' );
72
+ load_textdomain( 'wpo_wcpdf', $dir . 'plugins/wpo_wcpdf-' . $locale . '.mo' );
73
+ load_plugin_textdomain( 'wpo_wcpdf', false, dirname( self::$plugin_basename ) . '/languages' );
74
+ }
75
+
76
+ /**
77
+ * Load the main plugin classes and functions
78
+ */
79
+ public function includes() {
80
+ include_once( 'includes/class-wcpdf-settings.php' );
81
+ include_once( 'includes/class-wcpdf-writepanels.php' );
82
+ include_once( 'includes/class-wcpdf-export.php' );
83
+ }
84
+
85
+
86
+ /**
87
+ * Instantiate classes when woocommerce is activated
88
+ */
89
+ public function load_classes() {
90
+ if ( $this->is_woocommerce_activated() ) {
91
+ $this->includes();
92
+ $this->settings = new WooCommerce_PDF_Invoices_Settings();
93
+ $this->writepanels = new WooCommerce_PDF_Invoices_Writepanels();
94
+ $this->export = new WooCommerce_PDF_Invoices_Export();
95
+ } else {
96
+ // display notice instead
97
+ add_action( 'admin_notices', array ( $this, 'need_woocommerce' ) );
98
+ }
99
+
100
+ }
101
+
102
+ /**
103
+ * Check if woocommerce is activated
104
+ */
105
+ public function is_woocommerce_activated() {
106
+ $blog_plugins = get_option( 'active_plugins', array() );
107
+ $site_plugins = get_site_option( 'active_sitewide_plugins', array() );
108
+
109
+ if ( in_array( 'woocommerce/woocommerce.php', $blog_plugins ) || isset( $site_plugins['woocommerce/woocommerce.php'] ) ) {
110
+ return true;
111
+ } else {
112
+ return false;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * WooCommerce not active notice.
118
+ *
119
+ * @return string Fallack notice.
120
+ */
121
+
122
+ public function need_woocommerce() {
123
+ $error = sprintf( __( 'WooCommerce PDF Invoices & Packing Slips requires %sWooCommerce%s to be installed & activated!' , 'wpo_wcpdf' ), '<a href="http://wordpress.org/extend/plugins/woocommerce/">', '</a>' );
124
+
125
+ $message = '<div class="error"><p>' . $error . '</p></div>';
126
+
127
+ echo $message;
128
+ }
129
+
130
+ /** Lifecycle methods *******************************************************
131
+ * Because register_activation_hook only runs when the plugin is manually
132
+ * activated by the user, we're checking the current version against the
133
+ * version stored in the database
134
+ ****************************************************************************/
135
+
136
+ /**
137
+ * Handles version checking
138
+ */
139
+ public function do_install() {
140
+ // only install when woocommerce is active
141
+ if ( !$this->is_woocommerce_activated() ) {
142
+ return;
143
+ }
144
+
145
+ $version_setting = 'wpo_wcpdf_version';
146
+ $installed_version = get_option( $version_setting );
147
+
148
+ // installed version lower than plugin version?
149
+ if ( version_compare( $installed_version, self::$version, '<' ) ) {
150
+
151
+ if ( ! $installed_version ) {
152
+ $this->install();
153
+ } else {
154
+ $this->upgrade( $installed_version );
155
+ }
156
+
157
+ // new version number
158
+ update_option( $version_setting, self::$version );
159
+ }
160
+ }
161
+
162
+
163
+ /**
164
+ * Plugin install method. Perform any installation tasks here
165
+ */
166
+ protected function install() {
167
+ // Create temp folders
168
+ $tmp_base = $this->export->get_tmp_base();
169
+
170
+ // check if tmp folder exists => if not, initialize
171
+ if ( !@is_dir( $tmp_base ) ) {
172
+ $this->export->init_tmp( $tmp_base );
173
+ }
174
+
175
+ }
176
+
177
+
178
+ /**
179
+ * Plugin upgrade method. Perform any required upgrades here
180
+ *
181
+ * @param string $installed_version the currently installed version
182
+ */
183
+ protected function upgrade( $installed_version ) {
184
+ if ( $installed_version == 'versionless') { // versionless = 1.4.14 and older
185
+ // We're upgrading from an old version, so we're enabling the option to use the plugin tmp folder.
186
+ // This is not per se the 'best' solution, but the good thing is that nothing is changed
187
+ // and nothing will be broken (that wasn't broken before)
188
+ $default = array( 'old_tmp' => 1 );
189
+ update_option( 'wpo_wcpdf_debug_settings', $default );
190
+ }
191
+
192
+ // sync fonts on every upgrade!
193
+ $debug_settings = get_option( 'wpo_wcpdf_debug_settings' ); // get temp setting
194
+
195
+ // do not copy if old_tmp function active! (double check for slow databases)
196
+ if ( !( isset($this->debug_settings['old_tmp']) || $installed_version == 'versionless' ) ) {
197
+ $tmp_base = $this->export->get_tmp_base();
198
+
199
+ // check if tmp folder exists => if not, initialize
200
+ if ( !@is_dir( $tmp_base ) ) {
201
+ $this->export->init_tmp( $tmp_base );
202
+ }
203
+
204
+ $font_path = $tmp_base . 'fonts/';
205
+ $this->export->copy_fonts( $font_path );
206
+ }
207
+
208
+ // 1.5.28 update: copy next invoice number to separate setting
209
+ if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
210
+ $template_settings = get_option( 'wpo_wcpdf_template_settings' );
211
+ $next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
212
+ update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
213
+ }
214
+ }
215
+
216
+ /***********************************************************************/
217
+ /********************** GENERAL TEMPLATE FUNCTIONS *********************/
218
+ /***********************************************************************/
219
+
220
+ /**
221
+ * Get template name from slug
222
+ */
223
+ public function get_template_name ( $template_type ) {
224
+ switch ( $template_type ) {
225
+ case 'invoice':
226
+ $template_name = apply_filters( 'wpo_wcpdf_invoice_title', __( 'Invoice', 'wpo_wcpdf' ) );
227
+ break;
228
+ case 'packing-slip':
229
+ $template_name = apply_filters( 'wpo_wcpdf_packing_slip_title', __( 'Packing Slip', 'wpo_wcpdf' ) );
230
+ break;
231
+ default:
232
+ // try to 'unslug' the name
233
+ $template_name = ucwords( str_replace( array( '_', '-' ), ' ', $template_type ) );
234
+ break;
235
+ }
236
+
237
+ return apply_filters( 'wpo_wcpdf_template_name', $template_name, $template_type );
238
+ }
239
+
240
+ /**
241
+ * Output template styles
242
+ */
243
+ public function template_styles() {
244
+ $css = apply_filters( 'wpo_wcpdf_template_styles_file', $this->export->template_path. '/' .'style.css' );
245
+
246
+ ob_start();
247
+ if (file_exists($css)) {
248
+ include($css);
249
+ }
250
+ $html = ob_get_clean();
251
+ $html = apply_filters( 'wpo_wcpdf_template_styles', $html );
252
+
253
+ echo $html;
254
+ }
255
+
256
+ /**
257
+ * Return logo id
258
+ */
259
+ public function get_header_logo_id() {
260
+ if (isset($this->settings->template_settings['header_logo'])) {
261
+ return apply_filters( 'wpo_wcpdf_header_logo_id', $this->settings->template_settings['header_logo'] );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Show logo html
267
+ */
268
+ public function header_logo() {
269
+ if ($this->get_header_logo_id()) {
270
+ $attachment_id = $this->get_header_logo_id();
271
+ $company = isset($this->settings->template_settings['shop_name'])? $this->settings->template_settings['shop_name'] : '';
272
+ if( $attachment_id ) {
273
+ $attachment = wp_get_attachment_image_src( $attachment_id, 'full', false );
274
+
275
+ $attachment_src = $attachment[0];
276
+ $attachment_width = $attachment[1];
277
+ $attachment_height = $attachment[2];
278
+
279
+ $attachment_path = get_attached_file( $attachment_id );
280
+
281
+ if ( apply_filters('wpo_wcpdf_use_path', true) && file_exists($attachment_path) ) {
282
+ $src = $attachment_path;
283
+ } else {
284
+ $src = $attachment_src;
285
+ }
286
+
287
+ printf('<img src="%1$s" width="%2$d" height="%3$d" alt="%4$s" />', $src, $attachment_width, $attachment_height, esc_attr( $company ) );
288
+ }
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Return/Show custom company name or default to blog name
294
+ */
295
+ public function get_shop_name() {
296
+ if (!empty($this->settings->template_settings['shop_name'])) {
297
+ $name = trim( $this->settings->template_settings['shop_name'] );
298
+ return apply_filters( 'wpo_wcpdf_shop_name', wptexturize( $name ) );
299
+ } else {
300
+ return apply_filters( 'wpo_wcpdf_shop_name', get_bloginfo( 'name' ) );
301
+ }
302
+ }
303
+ public function shop_name() {
304
+ echo $this->get_shop_name();
305
+ }
306
+
307
+ /**
308
+ * Return/Show shop/company address if provided
309
+ */
310
+ public function get_shop_address() {
311
+ $shop_address = apply_filters( 'wpo_wcpdf_shop_address', wpautop( wptexturize( $this->settings->template_settings['shop_address'] ) ) );
312
+ if (!empty($shop_address)) {
313
+ return $shop_address;
314
+ } else {
315
+ return false;
316
+ }
317
+ }
318
+ public function shop_address() {
319
+ echo $this->get_shop_address();
320
+ }
321
+
322
+ /**
323
+ * Check if billing address and shipping address are equal
324
+ */
325
+ public function ships_to_different_address() {
326
+ // always prefer parent address for refunds
327
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
328
+ // temporarily switch order to make all filters / order calls work correctly
329
+ $order_meta = get_post_meta( $parent_order_id );
330
+ } else {
331
+ $order_meta = get_post_meta( $this->export->order->id );
332
+ }
333
+
334
+ $address_comparison_fields = apply_filters( 'wpo_wcpdf_address_comparison_fields', array(
335
+ 'first_name',
336
+ 'last_name',
337
+ 'company',
338
+ 'address_1',
339
+ 'address_2',
340
+ 'city',
341
+ 'state',
342
+ 'postcode',
343
+ 'country'
344
+ ) );
345
+
346
+ foreach ($address_comparison_fields as $address_field) {
347
+ $billing_field = isset( $order_meta['_billing_'.$address_field] ) ? $order_meta['_billing_'.$address_field] : '';
348
+ $shipping_field = isset( $order_meta['_shipping_'.$address_field] ) ? $order_meta['_shipping_'.$address_field] : '';
349
+ if ( $shipping_field != $billing_field ) {
350
+ // this address field is different -> ships to different address!
351
+ return true;
352
+ }
353
+ }
354
+
355
+ //if we got here, it means the addresses are equal -> doesn't ship to different address!
356
+ return apply_filters( 'wpo_wcpdf_ships_to_different_address', false, $order_meta );
357
+ }
358
+
359
+ /**
360
+ * Return/Show billing address
361
+ */
362
+ public function get_billing_address() {
363
+ // always prefer parent billing address for refunds
364
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
365
+ // temporarily switch order to make all filters / order calls work correctly
366
+ $current_order = $this->export->order;
367
+ $this->export->order = new WC_Order( $parent_order_id );
368
+ $address = apply_filters( 'wpo_wcpdf_billing_address', $this->export->order->get_formatted_billing_address() );
369
+ // switch back & unset
370
+ $this->export->order = $current_order;
371
+ unset($current_order);
372
+ } elseif ( $address = $this->export->order->get_formatted_billing_address() ) {
373
+ // regular shop_order
374
+ $address = apply_filters( 'wpo_wcpdf_billing_address', $address );
375
+ } else {
376
+ // no address
377
+ $address = apply_filters( 'wpo_wcpdf_billing_address', __('N/A', 'wpo_wcpdf') );
378
+ }
379
+
380
+ return $address;
381
+ }
382
+ public function billing_address() {
383
+ echo $this->get_billing_address();
384
+ }
385
+
386
+ /**
387
+ * Return/Show billing email
388
+ */
389
+ public function get_billing_email() {
390
+ $billing_email = $this->export->order->billing_email;
391
+
392
+ if ( !$billing_email && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
393
+ // try parent
394
+ $billing_email = get_post_meta( $parent_order_id, '_billing_email', true );
395
+ }
396
+
397
+ return apply_filters( 'wpo_wcpdf_billing_email', $billing_email );
398
+ }
399
+ public function billing_email() {
400
+ echo $this->get_billing_email();
401
+ }
402
+
403
+ /**
404
+ * Return/Show billing phone
405
+ */
406
+ public function get_billing_phone() {
407
+ $billing_phone = $this->export->order->billing_phone;
408
+
409
+ if ( !$billing_phone && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
410
+ // try parent
411
+ $billing_phone = get_post_meta( $parent_order_id, '_billing_phone', true );
412
+ }
413
+
414
+ return apply_filters( 'wpo_wcpdf_billing_phone', $billing_phone );
415
+ }
416
+ public function billing_phone() {
417
+ echo $this->get_billing_phone();
418
+ }
419
+
420
+ /**
421
+ * Return/Show shipping address
422
+ */
423
+ public function get_shipping_address() {
424
+ // always prefer parent shipping address for refunds
425
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
426
+ // temporarily switch order to make all filters / order calls work correctly
427
+ $current_order = $this->export->order;
428
+ $this->export->order = new WC_Order( $parent_order_id );
429
+ $address = apply_filters( 'wpo_wcpdf_shipping_address', $this->export->order->get_formatted_shipping_address() );
430
+ // switch back & unset
431
+ $this->export->order = $current_order;
432
+ unset($current_order);
433
+ } elseif ( $address = $this->export->order->get_formatted_shipping_address() ) {
434
+ // regular shop_order
435
+ $address = apply_filters( 'wpo_wcpdf_shipping_address', $address );
436
+ } else {
437
+ // no address
438
+ $address = apply_filters( 'wpo_wcpdf_shipping_address', __('N/A', 'wpo_wcpdf') );
439
+ }
440
+
441
+ return $address;
442
+ }
443
+ public function shipping_address() {
444
+ echo $this->get_shipping_address();
445
+ }
446
+
447
+ /**
448
+ * Return/Show a custom field
449
+ */
450
+ public function get_custom_field( $field_name ) {
451
+ $custom_field = get_post_meta($this->export->order->id,$field_name,true);
452
+
453
+ if ( !$custom_field && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
454
+ // try parent
455
+ $custom_field = get_post_meta( $parent_order_id, $field_name, true );
456
+ }
457
+
458
+ return apply_filters( 'wpo_wcpdf_billing_custom_field', $custom_field );
459
+ }
460
+ public function custom_field( $field_name, $field_label = '', $display_empty = false ) {
461
+ $custom_field = $this->get_custom_field( $field_name );
462
+ if (!empty($field_label)){
463
+ // add a a trailing space to the label
464
+ $field_label .= ' ';
465
+ }
466
+
467
+ if (!empty($custom_field) || $display_empty) {
468
+ echo $field_label . nl2br ($custom_field);
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Return/Show order notes
474
+ */
475
+ public function get_order_notes( $filter = 'customer' ) {
476
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
477
+ $post_id = $parent_order_id;
478
+ } else {
479
+ $post_id = $this->export->order->id;
480
+ }
481
+
482
+ $args = array(
483
+ 'post_id' => $post_id,
484
+ 'approve' => 'approve',
485
+ 'type' => 'order_note'
486
+ );
487
+
488
+ remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
489
+
490
+ $notes = get_comments( $args );
491
+
492
+ add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
493
+
494
+ if ( $notes ) {
495
+ foreach( $notes as $key => $note ) {
496
+ if ( $filter == 'customer' && !get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ) {
497
+ unset($notes[$key]);
498
+ }
499
+ if ( $filter == 'private' && get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ) {
500
+ unset($notes[$key]);
501
+ }
502
+ }
503
+ return $notes;
504
+ }
505
+ }
506
+ public function order_notes( $filter = 'customer' ) {
507
+ $notes = $this->get_order_notes( $filter );
508
+ if ( $notes ) {
509
+ foreach( $notes as $note ) {
510
+ ?>
511
+ <div class="note_content">
512
+ <?php echo wpautop( wptexturize( wp_kses_post( $note->comment_content ) ) ); ?>
513
+ </div>
514
+ <?php
515
+ }
516
+ }
517
+ }
518
+
519
+ /**
520
+ * Return/Show the current date
521
+ */
522
+ public function get_current_date() {
523
+ return apply_filters( 'wpo_wcpdf_date', date_i18n( get_option( 'date_format' ) ) );
524
+ }
525
+ public function current_date() {
526
+ echo $this->get_current_date();
527
+ }
528
+
529
+ /**
530
+ * Return/Show payment method
531
+ */
532
+ public function get_payment_method() {
533
+ $payment_method_label = __( 'Payment method', 'wpo_wcpdf' );
534
+
535
+ $payment_method = __( $this->export->order->payment_method_title, 'woocommerce' );
536
+ if ( !$payment_method && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
537
+ // try parent
538
+ $payment_method = get_post_meta( $parent_order_id, '_payment_method_title', true );
539
+ $payment_method = __( $payment_method, 'woocommerce' );
540
+ }
541
+
542
+ return apply_filters( 'wpo_wcpdf_payment_method', $payment_method );
543
+ }
544
+ public function payment_method() {
545
+ echo $this->get_payment_method();
546
+ }
547
+
548
+ /**
549
+ * Return/Show shipping method
550
+ */
551
+ public function get_shipping_method() {
552
+ $shipping_method_label = __( 'Shipping method', 'wpo_wcpdf' );
553
+ return apply_filters( 'wpo_wcpdf_shipping_method', __( $this->export->order->get_shipping_method(), 'woocommerce' ) );
554
+ }
555
+ public function shipping_method() {
556
+ echo $this->get_shipping_method();
557
+ }
558
+
559
+ /**
560
+ * Return/Show order number
561
+ */
562
+ public function get_order_number() {
563
+ // try parent first
564
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
565
+ $parent_order = new WC_Order( $parent_order_id );
566
+ $order_number = $parent_order->get_order_number();
567
+ } else {
568
+ $order_number = $this->export->order->get_order_number();
569
+ }
570
+
571
+ // Trim the hash to have a clean number but still
572
+ // support any filters that were applied before.
573
+ $order_number = ltrim($order_number, '#');
574
+ return apply_filters( 'wpo_wcpdf_order_number', $order_number);
575
+ }
576
+ public function order_number() {
577
+ echo $this->get_order_number();
578
+ }
579
+
580
+ /**
581
+ * Return/Show invoice number
582
+ */
583
+ public function get_invoice_number() {
584
+ // try parent first
585
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
586
+ $invoice_number = $this->export->get_invoice_number( $parent_order_id );
587
+ } else {
588
+ $invoice_number = $this->export->get_invoice_number( $this->export->order->id );
589
+ }
590
+
591
+ return $invoice_number;
592
+ }
593
+ public function invoice_number() {
594
+ echo $this->get_invoice_number();
595
+ }
596
+
597
+ /**
598
+ * Return/Show the order date
599
+ */
600
+ public function get_order_date() {
601
+ if ( get_post_type( $this->export->order->id ) == 'shop_order_refund' && $parent_order_id = wp_get_post_parent_id( $this->export->order->id ) ) {
602
+ $parent_order = new WC_Order( $parent_order_id );
603
+ $order_date = $parent_order->order_date;
604
+ } else {
605
+ $order_date = $this->export->order->order_date;
606
+ }
607
+
608
+ $date = date_i18n( get_option( 'date_format' ), strtotime( $order_date ) );
609
+ return apply_filters( 'wpo_wcpdf_order_date', $date, $order_date );
610
+ }
611
+ public function order_date() {
612
+ echo $this->get_order_date();
613
+ }
614
+
615
+ /**
616
+ * Return/Show the invoice date
617
+ */
618
+ public function get_invoice_date() {
619
+ $invoice_date = get_post_meta($this->export->order->id,'_wcpdf_invoice_date',true);
620
+
621
+ // add invoice date if it doesn't exist
622
+ if ( empty($invoice_date) || !isset($invoice_date) ) {
623
+ $invoice_date = current_time('mysql');
624
+ update_post_meta( $this->export->order->id, '_wcpdf_invoice_date', $invoice_date );
625
+ }
626
+
627
+ $formatted_invoice_date = date_i18n( get_option( 'date_format' ), strtotime( $invoice_date ) );
628
+
629
+ return apply_filters( 'wpo_wcpdf_invoice_date', $formatted_invoice_date, $invoice_date );
630
+ }
631
+ public function invoice_date() {
632
+ echo $this->get_invoice_date();
633
+ }
634
+
635
+ /**
636
+ * Return the order items
637
+ */
638
+ public function get_order_items() {
639
+ return apply_filters( 'wpo_wcpdf_order_items', $this->export->get_order_items() );
640
+ }
641
+
642
+ /**
643
+ * Return/show product attribute
644
+ */
645
+ public function get_product_attribute( $attribute_name, $product ) {
646
+ // first, check the text attributes
647
+ $attributes = $product->get_attributes();
648
+ $attribute_key = @wc_attribute_taxonomy_name( $attribute_name );
649
+ if (array_key_exists( sanitize_title( $attribute_name ), $attributes) ) {
650
+ $attribute = $product->get_attribute ( $attribute_name );
651
+ return $attribute;
652
+ } elseif (array_key_exists( sanitize_title( $attribute_key ), $attributes) ) {
653
+ $attribute = $product->get_attribute ( $attribute_key );
654
+ return $attribute;
655
+ }
656
+
657
+ // not a text attribute, try attribute taxonomy
658
+ $attribute_key = @wc_attribute_taxonomy_name( $attribute_name );
659
+ $product_terms = @wc_get_product_terms( $product->id, $attribute_key, array( 'fields' => 'names' ) );
660
+ // check if not empty, then display
661
+ if ( !empty($product_terms) ) {
662
+ $attribute = array_shift( $product_terms );
663
+ return $attribute;
664
+ } else {
665
+ // no attribute under this name
666
+ return false;
667
+ }
668
+ }
669
+ public function product_attribute( $attribute_name, $product ) {
670
+ echo $this->get_product_attribute( $attribute_name, $product );
671
+ }
672
+
673
+
674
+ /**
675
+ * Return the order totals listing
676
+ */
677
+ public function get_woocommerce_totals() {
678
+ // get totals and remove the semicolon
679
+ $totals = apply_filters( 'wpo_wcpdf_raw_order_totals', $this->export->order->get_order_item_totals(), $this->export->order );
680
+
681
+ // remove the colon for every label
682
+ foreach ( $totals as $key => $total ) {
683
+ $label = $total['label'];
684
+ $colon = strrpos( $label, ':' );
685
+ if( $colon !== false ) {
686
+ $label = substr_replace( $label, '', $colon, 1 );
687
+ }
688
+ $totals[$key]['label'] = $label;
689
+ }
690
+
691
+ // WC2.4 fix order_total for refunded orders
692
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '>=' ) && isset($totals['order_total']) ) {
693
+ $tax_display = $this->export->order->tax_display_cart;
694
+ $totals['order_total']['value'] = wc_price( $this->export->order->get_total(), array( 'currency' => $this->export->order->get_order_currency() ) );
695
+ $order_total = $this->export->order->get_total();
696
+ $tax_string = '';
697
+
698
+ // Tax for inclusive prices
699
+ if ( wc_tax_enabled() && 'incl' == $tax_display ) {
700
+ $tax_string_array = array();
701
+
702
+ if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) {
703
+ foreach ( $this->export->order->get_tax_totals() as $code => $tax ) {
704
+ $tax_amount = $tax->formatted_amount;
705
+ $tax_string_array[] = sprintf( '%s %s', $tax_amount, $tax->label );
706
+ }
707
+ } else {
708
+ $tax_string_array[] = sprintf( '%s %s', wc_price( $this->export->order->get_total_tax() - $this->export->order->get_total_tax_refunded(), array( 'currency' => $this->export->order->get_order_currency() ) ), WC()->countries->tax_or_vat() );
709
+ }
710
+ if ( ! empty( $tax_string_array ) ) {
711
+ $tax_string = ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) );
712
+ }
713
+ }
714
+
715
+ $totals['order_total']['value'] .= $tax_string;
716
+ }
717
+
718
+ return apply_filters( 'wpo_wcpdf_woocommerce_totals', $totals, $this->export->order );
719
+ }
720
+
721
+ /**
722
+ * Return/show the order subtotal
723
+ */
724
+ public function get_order_subtotal( $tax = 'excl', $discount = 'incl' ) { // set $tax to 'incl' to include tax, same for $discount
725
+ //$compound = ($discount == 'incl')?true:false;
726
+
727
+ $subtotal = $this->export->order->get_subtotal_to_display( false, $tax );
728
+
729
+ $subtotal = ($pos = strpos($subtotal, ' <small>')) ? substr($subtotal, 0, $pos) : $subtotal; //removing the 'excluding tax' text
730
+
731
+ $subtotal = array (
732
+ 'label' => __('Subtotal', 'wpo_wcpdf'),
733
+ 'value' => $subtotal,
734
+ );
735
+
736
+ return apply_filters( 'wpo_wcpdf_order_subtotal', $subtotal, $tax, $discount );
737
+ }
738
+ public function order_subtotal( $tax = 'excl', $discount = 'incl' ) {
739
+ $subtotal = $this->get_order_subtotal( $tax, $discount );
740
+ echo $subtotal['value'];
741
+ }
742
+
743
+ /**
744
+ * Return/show the order shipping costs
745
+ */
746
+ public function get_order_shipping( $tax = 'excl' ) { // set $tax to 'incl' to include tax
747
+ if ($tax == 'excl' ) {
748
+ $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping );
749
+ } else {
750
+ $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping + $this->export->order->order_shipping_tax );
751
+ }
752
+
753
+ $shipping = array (
754
+ 'label' => __('Shipping', 'wpo_wcpdf'),
755
+ 'value' => $shipping_costs,
756
+ 'tax' => $this->export->wc_price( $this->export->order->order_shipping_tax ),
757
+ );
758
+ return apply_filters( 'wpo_wcpdf_order_shipping', $shipping, $tax );
759
+ }
760
+ public function order_shipping( $tax = 'excl' ) {
761
+ $shipping = $this->get_order_shipping( $tax );
762
+ echo $shipping['value'];
763
+ }
764
+
765
+ /**
766
+ * Return/show the total discount
767
+ */
768
+ public function get_order_discount( $type = 'total', $tax = 'incl' ) {
769
+ if ( $tax == 'incl' ) {
770
+ switch ($type) {
771
+ case 'cart':
772
+ // Cart Discount - pre-tax discounts. (deprecated in WC2.3)
773
+ $discount_value = $this->export->order->get_cart_discount();
774
+ break;
775
+ case 'order':
776
+ // Order Discount - post-tax discounts. (deprecated in WC2.3)
777
+ $discount_value = $this->export->order->get_order_discount();
778
+ break;
779
+ case 'total':
780
+ // Total Discount
781
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
782
+ $discount_value = $this->export->order->get_total_discount( false ); // $ex_tax = false
783
+ } else {
784
+ // WC2.2 and older: recalculate to include tax
785
+ $discount_value = 0;
786
+ $items = $this->export->order->get_items();;
787
+ if( sizeof( $items ) > 0 ) {
788
+ foreach( $items as $item ) {
789
+ $discount_value += ($item['line_subtotal'] + $item['line_subtotal_tax']) - ($item['line_total'] + $item['line_tax']);
790
+ }
791
+ }
792
+ }
793
+
794
+ break;
795
+ default:
796
+ // Total Discount - Cart & Order Discounts combined
797
+ $discount_value = $this->export->order->get_total_discount();
798
+ break;
799
+ }
800
+ } else { // calculate discount excluding tax
801
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
802
+ $discount_value = $this->export->order->get_total_discount( true ); // $ex_tax = true
803
+ } else {
804
+ // WC2.2 and older: recalculate to exclude tax
805
+ $discount_value = 0;
806
+
807
+ $items = $this->export->order->get_items();;
808
+ if( sizeof( $items ) > 0 ) {
809
+ foreach( $items as $item ) {
810
+ $discount_value += ($item['line_subtotal'] - $item['line_total']);
811
+ }
812
+ }
813
+ }
814
+ }
815
+
816
+ $discount = array (
817
+ 'label' => __('Discount', 'wpo_wcpdf'),
818
+ 'value' => $this->export->wc_price($discount_value),
819
+ 'raw_value' => $discount_value,
820
+ );
821
+
822
+ if ( round( $discount_value, 3 ) != 0 ) {
823
+ return apply_filters( 'wpo_wcpdf_order_discount', $discount, $type, $tax );
824
+ }
825
+ }
826
+ public function order_discount( $type = 'total', $tax = 'incl' ) {
827
+ $discount = $this->get_order_discount( $type, $tax );
828
+ echo $discount['value'];
829
+ }
830
+
831
+ /**
832
+ * Return the order fees
833
+ */
834
+ public function get_order_fees( $tax = 'excl' ) {
835
+ if ( $wcfees = $this->export->order->get_fees() ) {
836
+ foreach( $wcfees as $id => $fee ) {
837
+ if ($tax == 'excl' ) {
838
+ $fee_price = $this->export->wc_price( $fee['line_total'] );
839
+ } else {
840
+ $fee_price = $this->export->wc_price( $fee['line_total'] + $fee['line_tax'] );
841
+ }
842
+
843
+ $fees[ $id ] = array(
844
+ 'label' => $fee['name'],
845
+ 'value' => $fee_price,
846
+ 'line_total' => $this->export->wc_price($fee['line_total']),
847
+ 'line_tax' => $this->export->wc_price($fee['line_tax'])
848
+ );
849
+ }
850
+ return $fees;
851
+ }
852
+ }
853
+
854
+ /**
855
+ * Return the order taxes
856
+ */
857
+ public function get_order_taxes() {
858
+ $tax_label = __( 'VAT', 'wpo_wcpdf' ); // register alternate label translation
859
+ $tax_label = __( 'Tax rate', 'wpo_wcpdf' );
860
+ $tax_rate_ids = $this->export->get_tax_rate_ids();
861
+ if ($this->export->order->get_taxes()) {
862
+ foreach ( $this->export->order->get_taxes() as $key => $tax ) {
863
+ $taxes[ $key ] = array(
864
+ 'label' => isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ],
865
+ 'value' => $this->export->wc_price( ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] ) ),
866
+ 'rate_id' => $tax['rate_id'],
867
+ 'tax_amount' => $tax['tax_amount'],
868
+ 'shipping_tax_amount' => $tax['shipping_tax_amount'],
869
+ 'rate' => isset( $tax_rate_ids[ $tax['rate_id'] ] ) ? ( (float) $tax_rate_ids[$tax['rate_id']]['tax_rate'] ) . ' %': '',
870
+ );
871
+ }
872
+
873
+ return apply_filters( 'wpo_wcpdf_order_taxes', $taxes );
874
+ }
875
+ }
876
+
877
+ /**
878
+ * Return/show the order grand total
879
+ */
880
+ public function get_order_grand_total( $tax = 'incl' ) {
881
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
882
+ // WC 2.1 or newer is used
883
+ $total_unformatted = $this->export->order->get_total();
884
+ } else {
885
+ // Backwards compatibility
886
+ $total_unformatted = $this->export->order->get_order_total();
887
+ }
888
+
889
+ if ($tax == 'excl' ) {
890
+ $total_tax = 0;
891
+ foreach ( $this->export->order->get_taxes() as $tax ) {
892
+ $total_tax += ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] );
893
+ }
894
+
895
+ $total = $this->export->wc_price( ( $total_unformatted - $total_tax ) );
896
+ $label = __( 'Total ex. VAT', 'wpo_wcpdf' );
897
+ } else {
898
+ $total = $this->export->wc_price( ( $total_unformatted ) );
899
+ $label = __( 'Total', 'wpo_wcpdf' );
900
+ }
901
+
902
+ $grand_total = array(
903
+ 'label' => $label,
904
+ 'value' => $total,
905
+ );
906
+
907
+ return apply_filters( 'wpo_wcpdf_order_grand_total', $grand_total, $tax );
908
+ }
909
+ public function order_grand_total( $tax = 'incl' ) {
910
+ $grand_total = $this->get_order_grand_total( $tax );
911
+ echo $grand_total['value'];
912
+ }
913
+
914
+
915
+ /**
916
+ * Return/Show shipping notes
917
+ */
918
+ public function get_shipping_notes() {
919
+ $shipping_notes = wpautop( wptexturize( $this->export->order->customer_note ) );
920
+ return apply_filters( 'wpo_wcpdf_shipping_notes', $shipping_notes );
921
+ }
922
+ public function shipping_notes() {
923
+ echo $this->get_shipping_notes();
924
+ }
925
+
926
+
927
+ /**
928
+ * Return/Show shop/company footer imprint, copyright etc.
929
+ */
930
+ public function get_footer() {
931
+ if (isset($this->settings->template_settings['footer'])) {
932
+ $footer = wpautop( wptexturize( $this->settings->template_settings[ 'footer' ] ) );
933
+ return apply_filters( 'wpo_wcpdf_footer', $footer );
934
+ }
935
+ }
936
+ public function footer() {
937
+ echo $this->get_footer();
938
+ }
939
+
940
+ /**
941
+ * Return/Show Extra field 1
942
+ */
943
+ public function get_extra_1() {
944
+ if (isset($this->settings->template_settings['extra_1'])) {
945
+ $extra_1 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_1' ] ) );
946
+ return apply_filters( 'wpo_wcpdf_extra_1', $extra_1 );
947
+ }
948
+ }
949
+ public function extra_1() {
950
+ echo $this->get_extra_1();
951
+ }
952
+
953
+ /**
954
+ * Return/Show Extra field 2
955
+ */
956
+ public function get_extra_2() {
957
+ if (isset($this->settings->template_settings['extra_2'])) {
958
+ $extra_2 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_2' ] ) );
959
+ return apply_filters( 'wpo_wcpdf_extra_2', $extra_2 );
960
+ }
961
+ }
962
+ public function extra_2() {
963
+ echo $this->get_extra_2();
964
+ }
965
+
966
+ /**
967
+ * Return/Show Extra field 3
968
+ */
969
+ public function get_extra_3() {
970
+ if (isset($this->settings->template_settings['extra_3'])) {
971
+ $extra_3 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_3' ] ) );
972
+ return apply_filters( 'wpo_wcpdf_extra_3', $extra_3 );
973
+ }
974
+ }
975
+ public function extra_3() {
976
+ echo $this->get_extra_3();
977
+ }
978
+ }
979
+ }
980
+
981
+ // Load main plugin class
982
+ $wpo_wcpdf = new WooCommerce_PDF_Invoices();