WooCommerce PDF Invoices & Packing Slips - Version 1.5.32

Version Description

  • Fix: Updated currency font with Indian Rupee symbol
  • Translations: added Formal German (currently a copy of informal German)
Download this release

Release Info

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

Code changes from version 1.5.31 to 1.5.32

includes/class-wcpdf-export.php CHANGED
@@ -1,1225 +1,1225 @@
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
- if ( isset($this->template_settings['currency_font'])) {
73
- add_action( 'wpo_wcpdf_before_pdf', array($this, 'use_currency_font' ) );
74
- }
75
-
76
-
77
- // WooCommerce Subscriptions compatibility
78
- if ( class_exists('WC_Subscriptions') ) {
79
- if ( version_compare( WC_Subscriptions::$version, '2.0', '<' ) ) {
80
- add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'woocommerce_subscriptions_renewal_order_created' ), 10, 4 );
81
- } else {
82
- add_action( 'wcs_renewal_order_created', array( $this, 'wcs_renewal_order_created' ), 10, 2 );
83
- }
84
- }
85
-
86
- // WooCommerce Product Bundles compatibility (add row classes)
87
- if ( class_exists('WC_Bundles') ) {
88
- add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
89
- }
90
-
91
- // WooCommerce Chained Products compatibility (add row classes)
92
- if ( class_exists('SA_WC_Chained_Products') ) {
93
- add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
94
- }
95
-
96
- // qTranslate-X compatibility
97
- if ( function_exists('qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
98
- $this->qtranslatex_filters();
99
- }
100
- }
101
-
102
- /**
103
- * Install/create plugin tmp folders
104
- */
105
- public function init_tmp ( $tmp_base ) {
106
- // create plugin base temp folder
107
- @mkdir( $tmp_base );
108
-
109
- // create subfolders & protect
110
- $subfolders = array( 'attachments', 'fonts', 'dompdf' );
111
- foreach ( $subfolders as $subfolder ) {
112
- $path = $tmp_base . $subfolder . '/';
113
- @mkdir( $path );
114
-
115
- // copy font files
116
- if ( $subfolder == 'fonts' ) {
117
- $this->copy_fonts( $path );
118
- }
119
-
120
- // create .htaccess file and empty index.php to protect in case an open webfolder is used!
121
- @file_put_contents( $path . '.htaccess', 'deny from all' );
122
- @touch( $path . 'index.php' );
123
- }
124
-
125
- }
126
-
127
- /**
128
- * Copy DOMPDF fonts to wordpress tmp folder
129
- */
130
- public function copy_fonts ( $path ) {
131
- $dompdf_font_dir = WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/lib/fonts/";
132
-
133
- // first try the easy way with glob!
134
- if ( function_exists('glob') ) {
135
- $files = glob($dompdf_font_dir."*.*");
136
- foreach($files as $file){
137
- if(!is_dir($file) && is_readable($file)) {
138
- $dest = $path . basename($file);
139
- copy($file, $dest);
140
- }
141
- }
142
- } else {
143
- // fallback method using font cache file (glob is disabled on some servers with disable_functions)
144
- $font_cache_file = $dompdf_font_dir . "dompdf_font_family_cache.php";
145
- $font_cache_dist_file = $dompdf_font_dir . "dompdf_font_family_cache.dist.php";
146
- $fonts = @require_once( $font_cache_file );
147
- $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm' );
148
-
149
- foreach ($fonts as $font_family => $filenames) {
150
- foreach ($filenames as $filename) {
151
- foreach ($extensions as $extension) {
152
- $file = $filename.$extension;
153
- if (file_exists($file)) {
154
- $dest = $path . basename($file);
155
- copy($file, $dest);
156
- }
157
- }
158
- }
159
- }
160
-
161
- // copy cache files separately
162
- copy($font_cache_file, $path.basename($font_cache_file));
163
- copy($font_cache_dist_file, $path.basename($font_cache_dist_file));
164
- }
165
-
166
- }
167
-
168
- /**
169
- * Return tmp path for different plugin processes
170
- */
171
- public function tmp_path ( $type = '' ) {
172
- // get temp setting
173
- $old_tmp = isset($this->debug_settings['old_tmp']);
174
-
175
- $tmp_base = $this->get_tmp_base();
176
- if (!$old_tmp) {
177
- // check if tmp folder exists => if not, initialize
178
- if ( !@is_dir( $tmp_base ) ) {
179
- $this->init_tmp( $tmp_base );
180
- }
181
- }
182
-
183
- if ( empty( $type ) ) {
184
- return $tmp_base;
185
- }
186
-
187
- switch ( $type ) {
188
- case 'DOMPDF_TEMP_DIR':
189
- // original value : sys_get_temp_dir()
190
- // 1.5+ : $tmp_base . 'dompdf'
191
- $tmp_path = $old_tmp ? sys_get_temp_dir() : $tmp_base . 'dompdf';
192
- break;
193
- case 'DOMPDF_FONT_DIR': // NEEDS TRAILING SLASH!
194
- // original value : DOMPDF_DIR."/lib/fonts/"
195
- // 1.5+ : $tmp_base . 'fonts/'
196
- $tmp_path = $old_tmp ? DOMPDF_DIR."/lib/fonts/" : $tmp_base . 'fonts/';
197
- break;
198
- case 'DOMPDF_FONT_CACHE':
199
- // original value : DOMPDF_FONT_DIR
200
- // 1.5+ : $tmp_base . 'fonts'
201
- $tmp_path = $old_tmp ? DOMPDF_FONT_DIR : $tmp_base . 'fonts';
202
- break;
203
- case 'attachments':
204
- // original value : WooCommerce_PDF_Invoices::$plugin_path . 'tmp/'
205
- // 1.5+ : $tmp_base . 'attachments/'
206
- $tmp_path = $old_tmp ? WooCommerce_PDF_Invoices::$plugin_path . 'tmp/' : $tmp_base . 'attachments/';
207
- break;
208
- default:
209
- $tmp_path = $tmp_base . $type;
210
- break;
211
- }
212
-
213
- // double check for existence, in case tmp_base was installed, but subfolder not created
214
- if ( !@is_dir( $tmp_path ) ) {
215
- @mkdir( $tmp_path );
216
- }
217
-
218
- return $tmp_path;
219
- }
220
-
221
- /**
222
- * return the base tmp folder (usually uploads)
223
- */
224
- public function get_tmp_base () {
225
- // wp_upload_dir() is used to set the base temp folder, under which a
226
- // 'wpo_wcpdf' folder and several subfolders are created
227
- //
228
- // wp_upload_dir() will:
229
- // * default to WP_CONTENT_DIR/uploads
230
- // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
231
- //
232
- // May also be overridden by the wpo_wcpdf_tmp_path filter
233
-
234
- $upload_dir = wp_upload_dir();
235
- $upload_base = trailingslashit( $upload_dir['basedir'] );
236
- $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
237
- return $tmp_base;
238
- }
239
-
240
- /**
241
- * Generate the template output
242
- */
243
- public function process_template( $template_type, $order_ids ) {
244
- $this->template_type = $template_type;
245
- $order_ids = apply_filters( 'wpo_wcpdf_process_order_ids', $order_ids, $template_type );
246
-
247
- // custom function fix
248
- if (function_exists('wpo_wcpdf_payment_form')) {
249
- return false;
250
- }
251
-
252
- // filter out trashed orders
253
- foreach ($order_ids as $key => $order_id) {
254
- $order_status = get_post_status( $order_id );
255
- if ( $order_status == 'trash' ) {
256
- unset( $order_ids[ $key ] );
257
- }
258
- }
259
- // sharing is caring!
260
- $this->order_ids = $order_ids;
261
-
262
- // throw error when no order ids
263
- if ( empty( $order_ids ) ) {
264
- throw new Exception('No orders to export!');
265
- }
266
-
267
- do_action( 'wpo_wcpdf_process_template', $template_type );
268
-
269
- $output_html = array();
270
- foreach ($order_ids as $order_id) {
271
- $this->order = new WC_Order( $order_id );
272
- do_action( 'wpo_wcpdf_process_template_order', $template_type, $order_id );
273
-
274
- $template = $this->template_path . '/' . $template_type . '.php';
275
- $template = apply_filters( 'wpo_wcpdf_template_file', $template, $template_type, $this->order );
276
-
277
- if (!file_exists($template)) {
278
- throw new Exception('Template not found! Check if the following file exists: <pre>'.$template.'</pre><br/>');
279
- }
280
-
281
- // Set the invoice number
282
- if ( $template_type == 'invoice' ) {
283
- $this->set_invoice_number( $order_id );
284
- }
285
-
286
- $output_html[$order_id] = $this->get_template($template);
287
-
288
- // store meta to be able to check if an invoice for an order has been created already
289
- if ( $template_type == 'invoice' ) {
290
- update_post_meta( $order_id, '_wcpdf_invoice_exists', 1 );
291
- }
292
-
293
-
294
- // Wipe post from cache
295
- wp_cache_delete( $order_id, 'posts' );
296
- wp_cache_delete( $order_id, 'post_meta' );
297
- }
298
-
299
- $print_script = "<script language=javascript>window.onload = function(){ window.print(); };</script>";
300
- // <div style="page-break-before: always;"></div>
301
- $page_break = "\n<div style=\"page-break-before: always;\"></div>\n";
302
-
303
-
304
- if (apply_filters('wpo_wcpdf_output_html', false, $template_type) && apply_filters('wpo_wcpdf_print_html', false, $template_type)) {
305
- $this->output_body = $print_script . implode($page_break, $output_html);
306
- } else {
307
- $this->output_body = implode($page_break, $output_html);
308
- }
309
-
310
- // Try to clean up a bit of memory
311
- unset($output_html);
312
-
313
- $template_wrapper = $this->template_path . '/html-document-wrapper.php';
314
-
315
- if (!file_exists($template_wrapper)) {
316
- throw new Exception('Template wrapper not found! Check if the following file exists: <pre>'.$template_wrapper.'</pre><br/>');
317
- }
318
-
319
- $complete_document = $this->get_template($template_wrapper);
320
-
321
- // Try to clean up a bit of memory
322
- unset($this->output_body);
323
-
324
- // clean up special characters
325
- $complete_document = utf8_decode(mb_convert_encoding($complete_document, 'HTML-ENTITIES', 'UTF-8'));
326
-
327
-
328
- return $complete_document;
329
- }
330
-
331
- /**
332
- * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
333
- */
334
- public function clear_page_number_styles ( $html, $template_type, $order_ids ) {
335
- $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">{{PAGE_COUNT}}</span>', $html);
336
- $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
337
- return $html;
338
- }
339
-
340
- /**
341
- * Replace {{PAGE_COUNT}} placeholder with total page count
342
- */
343
- public function page_number_replacements ( $dompdf, $html, $template_type, $order_ids ) {
344
- $placeholder = '{{PAGE_COUNT}}';
345
-
346
- // check if placeholder is used
347
- if (strpos($html, $placeholder) !== false ) {
348
- foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
349
- if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false) {
350
- $object["c"] = str_replace( $placeholder , $dompdf->get_canvas()->get_page_count() , $object["c"] );
351
- }
352
- }
353
- }
354
-
355
- return $dompdf;
356
- }
357
-
358
- /**
359
- * Create & render DOMPDF object
360
- */
361
- public function generate_pdf( $template_type, $order_ids ) {
362
- $paper_size = apply_filters( 'wpo_wcpdf_paper_format', $this->template_settings['paper_size'], $template_type );
363
- $paper_orientation = apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $template_type);
364
-
365
- do_action( 'wpo_wcpdf_before_pdf', $template_type );
366
- if ( !class_exists('DOMPDF') ) {
367
- // extra check to avoid clashes with other plugins using DOMPDF
368
- // This could have unwanted side-effects when the version that's already
369
- // loaded is different, and it could also miss fonts etc, but it's better
370
- // than not checking...
371
- require_once( WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/dompdf_config.inc.php" );
372
- }
373
-
374
- $dompdf = new DOMPDF();
375
- $html = apply_filters( 'wpo_wcpdf_processed_template_html', $this->process_template( $template_type, $order_ids ), $template_type, $order_ids );
376
- $dompdf->load_html( $html );
377
- $dompdf->set_paper( $paper_size, $paper_orientation );
378
- $dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $html, $template_type, $order_ids );
379
- $dompdf->render();
380
- $dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $html, $template_type, $order_ids );
381
- do_action( 'wpo_wcpdf_after_pdf', $template_type );
382
-
383
- // Try to clean up a bit of memory
384
- unset($complete_pdf);
385
-
386
- return $dompdf;
387
- }
388
-
389
- /**
390
- * Stream PDF
391
- */
392
- public function stream_pdf( $template_type, $order_ids, $filename ) {
393
- $dompdf = $this->generate_pdf( $template_type, $order_ids );
394
- $dompdf->stream($filename);
395
- }
396
-
397
- /**
398
- * Get PDF
399
- */
400
- public function get_pdf( $template_type, $order_ids ) {
401
- try {
402
- $dompdf = $this->generate_pdf( $template_type, $order_ids );
403
- return $dompdf->output();
404
- } catch (Exception $e) {
405
- echo $e->getMessage();
406
- return false;
407
- }
408
-
409
- }
410
-
411
- /**
412
- * Load and generate the template output with ajax
413
- */
414
- public function generate_pdf_ajax() {
415
- // Check the nonce
416
- if( empty( $_GET['action'] ) || ! is_user_logged_in() || !check_admin_referer( $_GET['action'] ) ) {
417
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
418
- }
419
-
420
- // Check if all parameters are set
421
- if( empty( $_GET['template_type'] ) || empty( $_GET['order_ids'] ) ) {
422
- wp_die( __( 'Some of the export parameters are missing.', 'wpo_wcpdf' ) );
423
- }
424
-
425
- $order_ids = (array) explode('x',$_GET['order_ids']);
426
- // Process oldest first: reverse $order_ids array
427
- $order_ids = array_reverse($order_ids);
428
-
429
- // Check the user privileges
430
- 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 ) ) {
431
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
432
- }
433
-
434
- // User call from my-account page
435
- if ( isset( $_GET['my-account'] ) ) {
436
- // Only for single orders!
437
- if ( count( $order_ids ) > 1 ) {
438
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
439
- }
440
-
441
- // Get user_id of order
442
- $this->order = new WC_Order ( $order_ids[0] );
443
-
444
- // Check if current user is owner of order IMPORTANT!!!
445
- if ( $this->order->user_id != get_current_user_id() ) {
446
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
447
- }
448
-
449
- // if we got here, we're safe to go!
450
- }
451
-
452
- // Generate the output
453
- $template_type = $_GET['template_type'];
454
- // die($this->process_template( $template_type, $order_ids )); // or use the filter switch below!
455
-
456
- if (apply_filters('wpo_wcpdf_output_html', false, $template_type)) {
457
- // Output html to browser for debug
458
- // NOTE! images will be loaded with the server path by default
459
- // use the wpo_wcpdf_use_path filter (return false) to change this to http urls
460
- die($this->process_template( $template_type, $order_ids ));
461
- }
462
-
463
- if ( !($pdf = $this->get_pdf( $template_type, $order_ids )) ) {
464
- exit;
465
- }
466
-
467
- $filename = $this->build_filename( $template_type, $order_ids, 'download' );
468
-
469
- do_action( 'wpo_wcpdf_created_manually', $pdf, $filename );
470
-
471
- // Get output setting
472
- $output_mode = isset($this->general_settings['download_display'])?$this->general_settings['download_display']:'';
473
-
474
- // Switch headers according to output setting
475
- if ( $output_mode == 'display' || empty($output_mode) ) {
476
- header('Content-type: application/pdf');
477
- header('Content-Disposition: inline; filename="'.$filename.'"');
478
- } else {
479
- header('Content-Description: File Transfer');
480
- header('Content-Type: application/octet-stream');
481
- header('Content-Disposition: attachment; filename="'.$filename.'"');
482
- header('Content-Transfer-Encoding: binary');
483
- header('Connection: Keep-Alive');
484
- header('Expires: 0');
485
- header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
486
- header('Pragma: public');
487
- }
488
-
489
- // output PDF data
490
- echo($pdf);
491
-
492
- exit;
493
- }
494
-
495
- /**
496
- * Build filename
497
- */
498
- public function build_filename( $template_type, $order_ids, $context ) {
499
- $count = count($order_ids);
500
-
501
- switch ($template_type) {
502
- case 'invoice':
503
- $name = _n( 'invoice', 'invoices', $count, 'wpo_wcpdf' );
504
- $number = $this->get_display_number( $order_ids[0] );
505
- break;
506
- case 'packing-slip':
507
- $name = _n( 'packing-slip', 'packing-slips', $count, 'wpo_wcpdf' );
508
- $number = $this->order->get_order_number();
509
- break;
510
- default:
511
- $name = $template_type;
512
- $number = $this->order->get_order_number();
513
- break;
514
- }
515
-
516
- if ( $count == 1 ) {
517
- $suffix = $number;
518
- } else {
519
- $suffix = date('Y-m-d'); // 2020-11-11
520
- }
521
-
522
- $filename = $name . '-' . $suffix . '.pdf';
523
-
524
- // Filter depending on context (for legacy filter support)
525
- if ( $context == 'download' ) {
526
- $filename = apply_filters( 'wpo_wcpdf_bulk_filename', $filename, $order_ids, $name, $template_type );
527
- } elseif ( $context == 'attachment' ) {
528
- $filename = apply_filters( 'wpo_wcpdf_attachment_filename', $filename, $number, $order_ids[0] );
529
- }
530
-
531
- // Filter filename (use this filter instead of the above legacy filters!)
532
- $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $template_type, $order_ids, $context );
533
-
534
- // sanitize filename (after filters to prevent human errors)!
535
- return sanitize_file_name( $filename );
536
- }
537
-
538
- /**
539
- * Attach invoice to completed order or customer invoice email
540
- */
541
- public function attach_pdf_to_email ( $attachments, $status, $order ) {
542
- // check if all variables properly set
543
- if ( !is_object( $order ) || !isset( $status ) ) {
544
- return $attachments;
545
- }
546
-
547
- // Skip User emails
548
- if ( get_class( $order ) == 'WP_User' ) {
549
- return $attachments;
550
- }
551
-
552
- // WooCommerce Booking compatibility
553
- if ( get_post_type( $order->id ) == 'wc_booking' && isset($order->order) ) {
554
- // $order is actually a WC_Booking object!
555
- $order = $order->order;
556
- }
557
-
558
- // do not process low stock notifications, user emails etc!
559
- if ( in_array( $status, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order->id ) != 'shop_order' ) {
560
- return $attachments;
561
- }
562
-
563
- // Disable free setting check
564
- $order_total = $order->get_total();
565
- if ( $order_total == 0 && isset($this->general_settings['disable_free']) ) {
566
- return $attachments;
567
- }
568
-
569
- $this->order = $order;
570
-
571
- $tmp_path = $this->tmp_path('attachments');
572
-
573
- // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
574
- array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
575
-
576
- // set allowed statuses for invoices
577
- $invoice_allowed = isset($this->general_settings['email_pdf']) ? array_keys( $this->general_settings['email_pdf'] ) : array();
578
- $documents = array(
579
- 'invoice' => apply_filters( 'wpo_wcpdf_email_allowed_statuses', $invoice_allowed ), // Relevant (default) statuses: new_order, customer_invoice, customer_processing_order, customer_completed_order
580
- );
581
- $documents = apply_filters('wpo_wcpdf_attach_documents', $documents );
582
-
583
- foreach ($documents as $template_type => $allowed_statuses ) {
584
- // convert 'lazy' status name
585
- foreach ($allowed_statuses as $key => $order_status) {
586
- if ($order_status == 'completed' || $order_status == 'processing') {
587
- $allowed_statuses[$key] = "customer_" . $order_status . "_order";
588
- }
589
- }
590
-
591
- // legacy filter, use wpo_wcpdf_custom_attachment_condition instead!
592
- $attach_invoice = apply_filters('wpo_wcpdf_custom_email_condition', true, $order, $status );
593
- if ( $template_type == 'invoice' && !$attach_invoice ) {
594
- // don't attach invoice, continue with other documents
595
- continue;
596
- }
597
-
598
- // use this filter to add an extra condition - return false to disable the PDF attachment
599
- $attach_document = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $status, $template_type );
600
- if( in_array( $status, $allowed_statuses ) && $attach_document ) {
601
- // create pdf data
602
- $pdf_data = $this->get_pdf( $template_type, (array) $order->id );
603
-
604
- if ( !$pdf_data ) {
605
- // something went wrong, continue trying with other documents
606
- continue;
607
- }
608
-
609
- // compose filename
610
- $pdf_filename = $this->build_filename( $template_type, (array) $order->id, 'attachment' );
611
-
612
- $pdf_path = $tmp_path . $pdf_filename;
613
- file_put_contents ( $pdf_path, $pdf_data );
614
- $attachments[] = $pdf_path;
615
-
616
- do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $template_type );
617
- }
618
- }
619
-
620
- return $attachments;
621
- }
622
-
623
- public function set_invoice_number( $order_id ) {
624
- // first check: get invoice number from post meta
625
- $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true );
626
-
627
- // add invoice number if it doesn't exist
628
- if ( empty($invoice_number) || !isset($invoice_number) ) {
629
- global $wpdb;
630
- // making direct DB call to avoid caching issues
631
- $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' ) );
632
- $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $next_invoice_number, $order_id );
633
-
634
- if ( empty($next_invoice_number) ) {
635
- // First time! We start numbering from order_number or order_id
636
-
637
- // Check if $order_number is an integer
638
- $order_number = ltrim($this->order->get_order_number(), '#');
639
- if ( ctype_digit( (string)$order_number ) ) {
640
- // order_number == integer: use as starting point.
641
- $invoice_number = $order_number;
642
- } else {
643
- // fallback: use order_id as starting point.
644
- $invoice_number = $order_id;
645
- }
646
-
647
- } else {
648
- $invoice_number = $next_invoice_number;
649
- }
650
-
651
- // reset invoice number yearly
652
- if ( isset( $this->template_settings['yearly_reset_invoice_number'] ) ) {
653
- $current_year = date("Y");
654
- $last_invoice_year = get_option( 'wpo_wcpdf_last_invoice_year' );
655
- // check first time use
656
- if ( empty( $last_invoice_year ) ) {
657
- $last_invoice_year = $current_year;
658
- update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
659
- }
660
- // check if we need to reset
661
- if ( $current_year != $last_invoice_year ) {
662
- $invoice_number = 1;
663
- update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
664
- }
665
- }
666
- // die($invoice_number);
667
-
668
- // invoice number logging
669
- // $order_number = ltrim($this->order->get_order_number(), '#');
670
- // $this->log( $order_id, "Invoice number {$invoice_number} set for order {$order_number} (id {$order_id})" );
671
-
672
- update_post_meta($order_id, '_wcpdf_invoice_number', $invoice_number);
673
- update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
674
-
675
- // increase next_order_number
676
- $update_args = array(
677
- 'option_value' => $invoice_number + 1,
678
- 'autoload' => 'yes',
679
- );
680
- $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => 'wpo_wcpdf_next_invoice_number' ) );
681
- }
682
-
683
- // store invoice_number in class object
684
- $this->invoice_number = $invoice_number;
685
-
686
- // store invoice number in _POST superglobal to prevent the number from being cleared in a save action
687
- // (http://wordpress.org/support/topic/customer-invoice-selection-from-order-detail-page-doesnt-record-invoice-id?replies=1)
688
- $_POST['_wcpdf_invoice_number'] = $invoice_number;
689
-
690
- return $invoice_number;
691
- }
692
-
693
- public function get_invoice_number( $order_id ) {
694
- // get invoice number from post meta
695
- if ( $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true ) ) {
696
- // check if we have already loaded this order
697
- if ( $this->order->id == $order_id ) {
698
- $order_number = $this->order->get_order_number();
699
- $order_date = $this->order->order_date;
700
- } else {
701
- $order = new WC_Order( $order_id );
702
- $order_number = $order->get_order_number();
703
- $order_date = $order->order_date;
704
- }
705
-
706
- return apply_filters( 'wpo_wcpdf_invoice_number', $invoice_number, $order_number, $order_id, $order_date );
707
- } else {
708
- // no invoice number for this order
709
- return false;
710
- }
711
- }
712
-
713
- /**
714
- * Add invoice number to WC REST API
715
- */
716
- public function woocommerce_api_invoice_numer ( $data, $order ) {
717
- if ( $invoice_number = $this->get_invoice_number( $order->id ) ) {
718
- $data['wpo_wcpdf_invoice_number'] = $invoice_number;
719
- } else {
720
- $data['wpo_wcpdf_invoice_number'] = '';
721
- }
722
- return $data;
723
- }
724
-
725
- /**
726
- * Reset invoice data for WooCommerce subscription renewal orders
727
- * https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
728
- */
729
- public function woocommerce_subscriptions_renewal_order_created ( $renewal_order, $original_order, $product_id, $new_order_role ) {
730
- $this->reset_invoice_data( $renewal_order->id );
731
- return $renewal_order;
732
- }
733
-
734
- public function wcs_renewal_order_created ( $renewal_order, $subscription ) {
735
- $this->reset_invoice_data( $renewal_order->id );
736
- return $renewal_order;
737
- }
738
-
739
- public function reset_invoice_data ( $order_id ) {
740
- // delete invoice number, invoice date & invoice exists meta
741
- delete_post_meta( $order_id, '_wcpdf_invoice_number' );
742
- delete_post_meta( $order_id, '_wcpdf_formatted_invoice_number' );
743
- delete_post_meta( $order_id, '_wcpdf_invoice_date' );
744
- delete_post_meta( $order_id, '_wcpdf_invoice_exists' );
745
- }
746
-
747
- public function format_invoice_number( $invoice_number, $order_number, $order_id, $order_date ) {
748
- // get format settings
749
- $formats['prefix'] = isset($this->template_settings['invoice_number_formatting_prefix'])?$this->template_settings['invoice_number_formatting_prefix']:'';
750
- $formats['suffix'] = isset($this->template_settings['invoice_number_formatting_suffix'])?$this->template_settings['invoice_number_formatting_suffix']:'';
751
- $formats['padding'] = isset($this->template_settings['invoice_number_formatting_padding'])?$this->template_settings['invoice_number_formatting_padding']:'';
752
-
753
- // Replacements
754
- $order_year = date_i18n( 'Y', strtotime( $order_date ) );
755
- $order_month = date_i18n( 'm', strtotime( $order_date ) );
756
- $order_day = date_i18n( 'd', strtotime( $order_date ) );
757
- $invoice_date = get_post_meta($order_id,'_wcpdf_invoice_date',true);
758
- $invoice_date = empty($invoice_date) ? current_time('mysql') : $invoice_date;
759
- $invoice_year = date_i18n( 'Y', strtotime( $invoice_date ) );
760
- $invoice_month = date_i18n( 'm', strtotime( $invoice_date ) );
761
- $invoice_day = date_i18n( 'd', strtotime( $invoice_date ) );
762
-
763
- foreach ($formats as $key => $value) {
764
- $value = str_replace('[order_year]', $order_year, $value);
765
- $value = str_replace('[order_month]', $order_month, $value);
766
- $value = str_replace('[order_day]', $order_day, $value);
767
- $value = str_replace('[invoice_year]', $invoice_year, $value);
768
- $value = str_replace('[invoice_month]', $invoice_month, $value);
769
- $value = str_replace('[invoice_day]', $invoice_day, $value);
770
- $formats[$key] = $value;
771
- }
772
-
773
- // Padding
774
- if ( ctype_digit( (string)$formats['padding'] ) ) {
775
- $invoice_number = sprintf('%0'.$formats['padding'].'d', $invoice_number);
776
- }
777
-
778
- $formatted_invoice_number = $formats['prefix'] . $invoice_number . $formats['suffix'] ;
779
-
780
- return $formatted_invoice_number;
781
- }
782
-
783
- public function get_display_number( $order_id ) {
784
- if ( !isset($this->order->id) ) {
785
- $this->order = new WC_Order ( $order_id );
786
- }
787
-
788
- if ( isset($this->template_settings['display_number']) && $this->template_settings['display_number'] == 'invoice_number' ) {
789
- // use invoice number
790
- $display_number = $this->get_invoice_number( $order_id );
791
- // die($display_number);
792
- } else {
793
- // use order number
794
- $display_number = ltrim($this->order->get_order_number(), '#');
795
- }
796
-
797
- return $display_number;
798
- }
799
-
800
- /**
801
- * Return evaluated template contents
802
- */
803
- public function get_template( $file ) {
804
- ob_start();
805
- if (file_exists($file)) {
806
- include($file);
807
- }
808
- return ob_get_clean();
809
- }
810
-
811
- /**
812
- * Get the current order
813
- */
814
- public function get_order() {
815
- return $this->order;
816
- }
817
-
818
- /**
819
- * Get the current order items
820
- */
821
- public function get_order_items() {
822
- global $woocommerce;
823
- global $_product;
824
-
825
- $items = $this->order->get_items();
826
- $data_list = array();
827
-
828
- if( sizeof( $items ) > 0 ) {
829
- foreach ( $items as $item_id => $item ) {
830
- // Array with data for the pdf template
831
- $data = array();
832
-
833
- // Set the item_id
834
- $data['item_id'] = $item_id;
835
-
836
- // Set the id
837
- $data['product_id'] = $item['product_id'];
838
- $data['variation_id'] = $item['variation_id'];
839
-
840
- // Set item name
841
- $data['name'] = $item['name'];
842
-
843
- // Set item quantity
844
- $data['quantity'] = $item['qty'];
845
-
846
- // Set the line total (=after discount)
847
- $data['line_total'] = $this->wc_price( $item['line_total'] );
848
- $data['single_line_total'] = $this->wc_price( $item['line_total'] / max( 1, $item['qty'] ) );
849
- $data['line_tax'] = $this->wc_price( $item['line_tax'] );
850
- $data['single_line_tax'] = $this->wc_price( $item['line_tax'] / max( 1, $item['qty'] ) );
851
-
852
- $line_tax_data = maybe_unserialize( isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '' );
853
- $data['tax_rates'] = $this->get_tax_rate( $item['tax_class'], $item['line_total'], $item['line_tax'], $line_tax_data );
854
-
855
- // Set the line subtotal (=before discount)
856
- $data['line_subtotal'] = $this->wc_price( $item['line_subtotal'] );
857
- $data['line_subtotal_tax'] = $this->wc_price( $item['line_subtotal_tax'] );
858
- $data['ex_price'] = $this->get_formatted_item_price ( $item, 'total', 'excl' );
859
- $data['price'] = $this->get_formatted_item_price ( $item, 'total' );
860
- $data['order_price'] = $this->order->get_formatted_line_subtotal( $item ); // formatted according to WC settings
861
-
862
- // Calculate the single price with the same rules as the formatted line subtotal (!)
863
- // = before discount
864
- $data['ex_single_price'] = $this->get_formatted_item_price ( $item, 'single', 'excl' );
865
- $data['single_price'] = $this->get_formatted_item_price ( $item, 'single' );
866
-
867
- // Pass complete item array
868
- $data['item'] = $item;
869
-
870
- // Create the product to display more info
871
- $data['product'] = null;
872
-
873
- $product = $this->order->get_product_from_item( $item );
874
-
875
- // Checking fo existance, thanks to MDesigner0
876
- if(!empty($product)) {
877
- // Set the thumbnail id DEPRICATED (does not support thumbnail sizes), use thumbnail_path or thumbnail instead
878
- $data['thumbnail_id'] = $this->get_thumbnail_id( $product );
879
-
880
- // Thumbnail (full img tag)
881
- $data['thumbnail'] = $this->get_thumbnail ( $product );
882
-
883
- // Set the single price (turned off to use more consistent calculated price)
884
- // $data['single_price'] = woocommerce_price ( $product->get_price() );
885
-
886
- // Set item SKU
887
- $data['sku'] = $product->get_sku();
888
-
889
- // Set item weight
890
- $data['weight'] = $product->get_weight();
891
-
892
- // Set item dimensions
893
- $data['dimensions'] = $product->get_dimensions();
894
-
895
- // Pass complete product object
896
- $data['product'] = $product;
897
-
898
- }
899
-
900
- // Set item meta
901
- if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
902
- $meta = new WC_Order_Item_Meta( $item['item_meta'], $product );
903
- } else {
904
- // pass complete item for WC2.4+
905
- $meta = new WC_Order_Item_Meta( $item, $product );
906
- }
907
-
908
- $data['meta'] = $meta->display( false, true );
909
-
910
- $data_list[$item_id] = apply_filters( 'wpo_wcpdf_order_item_data', $data, $this->order );
911
- }
912
- }
913
-
914
- return apply_filters( 'wpo_wcpdf_order_items_data', $data_list, $this->order );
915
- }
916
-
917
- /**
918
- * Gets price - formatted for display.
919
- *
920
- * @access public
921
- * @param mixed $item
922
- * @return string
923
- */
924
- public function get_formatted_item_price ( $item, $type, $tax_display = '' ) {
925
- $item_price = 0;
926
- $divider = ($type == 'single' && $item['qty'] != 0 )?$item['qty']:1; //divide by 1 if $type is not 'single' (thus 'total')
927
-
928
- if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) )
929
- return;
930
-
931
- if ( $tax_display == 'excl' ) {
932
- $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item )) / $divider );
933
- } else {
934
- $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item, true )) / $divider );
935
- }
936
-
937
- return $item_price;
938
- }
939
-
940
- /**
941
- * wrapper for wc2.1 depricated price function
942
- */
943
- public function wc_price( $price, $args = array() ) {
944
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
945
- // WC 2.1 or newer is used
946
- $args['currency'] = $this->order->get_order_currency();
947
- $formatted_price = wc_price( $price, $args );
948
- } else {
949
- $formatted_price = woocommerce_price( $price );
950
- }
951
-
952
- return $formatted_price;
953
- }
954
-
955
- /**
956
- * Get the tax rates/percentages for a given tax class
957
- * @param string $tax_class tax class slug
958
- * @return string $tax_rates imploded list of tax rates
959
- */
960
- public function get_tax_rate( $tax_class, $line_total, $line_tax, $line_tax_data = '' ) {
961
- if ( $line_tax == 0 ) {
962
- return '-'; // no need to determine tax rate...
963
- }
964
-
965
- // first try the easy wc2.2 way, using line_tax_data
966
- if ( !empty( $line_tax_data ) && isset($line_tax_data['total']) ) {
967
- $tax_rates = array();
968
-
969
- $line_taxes = $line_tax_data['total'];
970
- foreach ( $line_taxes as $tax_id => $tax ) {
971
- if ( !empty($tax) && $tax != 0 ) {
972
- $tax_rates[] = $this->get_tax_rate_by_id( $tax_id ) . ' %';
973
- }
974
- }
975
-
976
- $tax_rates = implode(' ,', $tax_rates );
977
- return $tax_rates;
978
- }
979
-
980
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 && !apply_filters( 'wpo_wcpdf_calculate_tax_rate', false ) ) {
981
- // WC 2.1 or newer is used
982
-
983
- // if (empty($tax_class))
984
- // $tax_class = 'standard';// does not appear to work anymore - get_rates does accept an empty tax_class though!
985
-
986
- $tax = new WC_Tax();
987
- $taxes = $tax->get_rates( $tax_class );
988
-
989
- $tax_rates = array();
990
-
991
- foreach ($taxes as $tax) {
992
- $tax_rates[$tax['label']] = round( $tax['rate'], 2 ).' %';
993
- }
994
-
995
- if (empty($tax_rates)) {
996
- // one last try: manually calculate
997
- if ( $line_total != 0) {
998
- $tax_rates[] = round( ($line_tax / $line_total)*100, 1 ).' %';
999
- } else {
1000
- $tax_rates[] = '-';
1001
- }
1002
- }
1003
-
1004
- $tax_rates = implode(' ,', $tax_rates );
1005
- } else {
1006
- // Backwards compatibility/fallback: calculate tax from line items
1007
- if ( $line_total != 0) {
1008
- $tax_rates = round( ($line_tax / $line_total)*100, 1 ).' %';
1009
- } else {
1010
- $tax_rates = '-';
1011
- }
1012
- }
1013
-
1014
- return $tax_rates;
1015
- }
1016
-
1017
- /**
1018
- * Returns the percentage rate (float) for a given tax rate ID.
1019
- * @param int $rate_id woocommerce tax rate id
1020
- * @return float $rate percentage rate
1021
- */
1022
- public function get_tax_rate_by_id( $rate_id ) {
1023
- global $wpdb;
1024
- $rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) );
1025
- return (float) $rate;
1026
- }
1027
-
1028
- /**
1029
- * Returns a an array with rate_id => tax rate data (array) of all tax rates in woocommerce
1030
- * @return array $tax_rate_ids keyed by id
1031
- */
1032
- public function get_tax_rate_ids() {
1033
- global $wpdb;
1034
- $rates = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates" );
1035
-
1036
- $tax_rate_ids = array();
1037
- foreach ($rates as $rate) {
1038
- // var_dump($rate->tax_rate_id);
1039
- // die($rate);
1040
- $rate_id = $rate->tax_rate_id;
1041
- unset($rate->tax_rate_id);
1042
- $tax_rate_ids[$rate_id] = (array) $rate;
1043
- }
1044
-
1045
- return $tax_rate_ids;
1046
- }
1047
-
1048
- /**
1049
- * Get order custom field
1050
- */
1051
- public function get_order_field( $field ) {
1052
- if( isset( $this->get_order()->order_custom_fields[$field] ) ) {
1053
- return $this->get_order()->order_custom_fields[$field][0];
1054
- }
1055
- return;
1056
- }
1057
-
1058
- /**
1059
- * Returns the main product image ID
1060
- * Adapted from the WC_Product class
1061
- *
1062
- * @access public
1063
- * @return string
1064
- */
1065
- public function get_thumbnail_id ( $product ) {
1066
- // DEPRICATED (does not support thumbnail sizes)
1067
- global $woocommerce;
1068
-
1069
- if ( $product->variation_id && has_post_thumbnail( $product->variation_id ) ) {
1070
- $thumbnail_id = get_post_thumbnail_id ( $product->variation_id );
1071
- } elseif ( has_post_thumbnail( $product->id ) ) {
1072
- $thumbnail_id = get_post_thumbnail_id ( $product->id );
1073
- } elseif ( ( $parent_id = wp_get_post_parent_id( $product->id ) ) && has_post_thumbnail( $parent_id ) ) {
1074
- $thumbnail_id = get_post_thumbnail_id ( $parent_id );
1075
- } else {
1076
- $thumbnail_id = $woocommerce->plugin_url() . '/assets/images/placeholder.png';
1077
- }
1078
-
1079
- return $thumbnail_id;
1080
- }
1081
-
1082
- public function get_thumbnail ( $product ) {
1083
- // Get default WooCommerce img tag (url/http)
1084
- $size = apply_filters( 'wpo_wcpdf_thumbnail_size', 'shop_thumbnail' );
1085
- $thumbnail_img_tag_url = $product->get_image( $size, array( 'title' => '' ) );
1086
-
1087
- // Extract the url from img
1088
- preg_match('/<img(.*)src(.*)=(.*)"(.*)"/U', $thumbnail_img_tag_url, $thumbnail_url );
1089
- // convert url to path
1090
- $thumbnail_path = str_replace( get_site_url() . '/', ABSPATH, array_pop($thumbnail_url));
1091
-
1092
- // Thumbnail (full img tag)
1093
- if (apply_filters('wpo_wcpdf_use_path', true) && file_exists($thumbnail_path)) {
1094
- // load img with server path by default
1095
- $thumbnail = sprintf('<img width="90" height="90" src="%s" class="attachment-shop_thumbnail wp-post-image">', $thumbnail_path );
1096
- } else {
1097
- // load img with http url when filtered
1098
- $thumbnail = $thumbnail_img_tag_url;
1099
- }
1100
-
1101
- // die($thumbnail);
1102
-
1103
- return $thumbnail;
1104
- }
1105
-
1106
- public function add_product_bundles_classes ( $classes, $template_type, $order, $item_id = '' ) {
1107
- if ( empty($item_id) ) {
1108
- // get item id from classes (backwards compatibility fix)
1109
- $class_array = explode(' ', $classes);
1110
- foreach ($class_array as $class) {
1111
- if (is_numeric($class)) {
1112
- $item_id = $class;
1113
- break;
1114
- }
1115
- }
1116
-
1117
- // if still empty, we lost the item id somewhere :(
1118
- if (empty($item_id)) {
1119
- return $classes;
1120
- }
1121
- }
1122
-
1123
- $item_meta = $order->get_item_meta( $item_id );
1124
-
1125
- if (isset($item_meta['_bundled_by'])) {
1126
- $classes = $classes . ' bundled-item';
1127
-
1128
- // check bundled item visibility
1129
- if ( ! empty( $item_meta[ '_bundled_item_hidden' ] ) ) {
1130
- $classes = $classes . ' hidden';
1131
- }
1132
-
1133
- return $classes;
1134
- } elseif (isset($item_meta['_bundled_items'])) {
1135
- return $classes . ' product-bundle';
1136
- }
1137
-
1138
- return $classes;
1139
- }
1140
-
1141
- public function add_chained_product_class ( $classes, $template_type, $order, $item_id = '' ) {
1142
- if ( empty($item_id) ) {
1143
- // get item id from classes (backwards compatibility fix)
1144
- $class_array = explode(' ', $classes);
1145
- foreach ($class_array as $class) {
1146
- if (is_numeric($class)) {
1147
- $item_id = $class;
1148
- break;
1149
- }
1150
- }
1151
-
1152
- // if still empty, we lost the item id somewhere :(
1153
- if (empty($item_id)) {
1154
- return $classes;
1155
- }
1156
- }
1157
-
1158
- $item_meta = $order->get_item_meta( $item_id );
1159
-
1160
- if (isset($item_meta['_chained_product_of'])) {
1161
- return $classes . ' chained-product';
1162
- }
1163
-
1164
- return $classes;
1165
- }
1166
-
1167
- /**
1168
- * Filter plugin strings with qTranslate-X
1169
- */
1170
- public function qtranslatex_filters() {
1171
- $use_filters = array(
1172
- 'wpo_wcpdf_shop_name' => 20,
1173
- 'wpo_wcpdf_shop_address' => 20,
1174
- 'wpo_wcpdf_footer' => 20,
1175
- 'wpo_wcpdf_order_items' => 20,
1176
- 'wpo_wcpdf_payment_method' => 20,
1177
- 'wpo_wcpdf_shipping_method' => 20,
1178
- 'wpo_wcpdf_extra_1' => 20,
1179
- 'wpo_wcpdf_extra_2' => 20,
1180
- 'wpo_wcpdf_extra_3' => 20,
1181
- );
1182
-
1183
- foreach ( $use_filters as $name => $priority ) {
1184
- add_filter( $name, 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage', $priority );
1185
- }
1186
- }
1187
-
1188
- /**
1189
- * Use currency symbol font (when enabled in options)
1190
- */
1191
- public function use_currency_font ( $template_type ) {
1192
- add_filter( 'woocommerce_currency_symbol', array( $this, 'wrap_currency_symbol' ), 10, 2);
1193
- add_action( 'wpo_wcpdf_custom_styles', array($this, 'currency_symbol_font_styles' ) );
1194
- }
1195
-
1196
- public function wrap_currency_symbol( $currency_symbol, $currency ) {
1197
- $currency_symbol = sprintf( '<span class="wcpdf-currency-symbol">%s</span>', $currency_symbol );
1198
- return $currency_symbol;
1199
- }
1200
-
1201
- public function currency_symbol_font_styles () {
1202
- ?>
1203
- .wcpdf-currency-symbol { font-family: 'Currencies'; }
1204
- <?php
1205
- }
1206
-
1207
- public function enable_debug () {
1208
- error_reporting( E_ALL );
1209
- ini_set( 'display_errors', 1 );
1210
- }
1211
-
1212
- /**
1213
- * Log messages
1214
- */
1215
-
1216
- public function log( $order_id, $message ) {
1217
- $current_date_time = date("Y-m-d H:i:s");
1218
- $message = $order_id . ' ' . $current_date_time .' ' .$message ."\n";
1219
- $file = $this->tmp_path() . 'log.txt';
1220
-
1221
- file_put_contents($file, $message, FILE_APPEND);
1222
- }
1223
- }
1224
-
1225
- }
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
+ if ( isset($this->template_settings['currency_font'])) {
73
+ add_action( 'wpo_wcpdf_before_pdf', array($this, 'use_currency_font' ) );
74
+ }
75
+
76
+
77
+ // WooCommerce Subscriptions compatibility
78
+ if ( class_exists('WC_Subscriptions') ) {
79
+ if ( version_compare( WC_Subscriptions::$version, '2.0', '<' ) ) {
80
+ add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'woocommerce_subscriptions_renewal_order_created' ), 10, 4 );
81
+ } else {
82
+ add_action( 'wcs_renewal_order_created', array( $this, 'wcs_renewal_order_created' ), 10, 2 );
83
+ }
84
+ }
85
+
86
+ // WooCommerce Product Bundles compatibility (add row classes)
87
+ if ( class_exists('WC_Bundles') ) {
88
+ add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
89
+ }
90
+
91
+ // WooCommerce Chained Products compatibility (add row classes)
92
+ if ( class_exists('SA_WC_Chained_Products') ) {
93
+ add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
94
+ }
95
+
96
+ // qTranslate-X compatibility
97
+ if ( function_exists('qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
98
+ $this->qtranslatex_filters();
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Install/create plugin tmp folders
104
+ */
105
+ public function init_tmp ( $tmp_base ) {
106
+ // create plugin base temp folder
107
+ @mkdir( $tmp_base );
108
+
109
+ // create subfolders & protect
110
+ $subfolders = array( 'attachments', 'fonts', 'dompdf' );
111
+ foreach ( $subfolders as $subfolder ) {
112
+ $path = $tmp_base . $subfolder . '/';
113
+ @mkdir( $path );
114
+
115
+ // copy font files
116
+ if ( $subfolder == 'fonts' ) {
117
+ $this->copy_fonts( $path );
118
+ }
119
+
120
+ // create .htaccess file and empty index.php to protect in case an open webfolder is used!
121
+ @file_put_contents( $path . '.htaccess', 'deny from all' );
122
+ @touch( $path . 'index.php' );
123
+ }
124
+
125
+ }
126
+
127
+ /**
128
+ * Copy DOMPDF fonts to wordpress tmp folder
129
+ */
130
+ public function copy_fonts ( $path ) {
131
+ $dompdf_font_dir = WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/lib/fonts/";
132
+
133
+ // first try the easy way with glob!
134
+ if ( function_exists('glob') ) {
135
+ $files = glob($dompdf_font_dir."*.*");
136
+ foreach($files as $file){
137
+ if(!is_dir($file) && is_readable($file)) {
138
+ $dest = $path . basename($file);
139
+ copy($file, $dest);
140
+ }
141
+ }
142
+ } else {
143
+ // fallback method using font cache file (glob is disabled on some servers with disable_functions)
144
+ $font_cache_file = $dompdf_font_dir . "dompdf_font_family_cache.php";
145
+ $font_cache_dist_file = $dompdf_font_dir . "dompdf_font_family_cache.dist.php";
146
+ $fonts = @require_once( $font_cache_file );
147
+ $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm' );
148
+
149
+ foreach ($fonts as $font_family => $filenames) {
150
+ foreach ($filenames as $filename) {
151
+ foreach ($extensions as $extension) {
152
+ $file = $filename.$extension;
153
+ if (file_exists($file)) {
154
+ $dest = $path . basename($file);
155
+ copy($file, $dest);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ // copy cache files separately
162
+ copy($font_cache_file, $path.basename($font_cache_file));
163
+ copy($font_cache_dist_file, $path.basename($font_cache_dist_file));
164
+ }
165
+
166
+ }
167
+
168
+ /**
169
+ * Return tmp path for different plugin processes
170
+ */
171
+ public function tmp_path ( $type = '' ) {
172
+ // get temp setting
173
+ $old_tmp = isset($this->debug_settings['old_tmp']);
174
+
175
+ $tmp_base = $this->get_tmp_base();
176
+ if (!$old_tmp) {
177
+ // check if tmp folder exists => if not, initialize
178
+ if ( !@is_dir( $tmp_base ) ) {
179
+ $this->init_tmp( $tmp_base );
180
+ }
181
+ }
182
+
183
+ if ( empty( $type ) ) {
184
+ return $tmp_base;
185
+ }
186
+
187
+ switch ( $type ) {
188
+ case 'DOMPDF_TEMP_DIR':
189
+ // original value : sys_get_temp_dir()
190
+ // 1.5+ : $tmp_base . 'dompdf'
191
+ $tmp_path = $old_tmp ? sys_get_temp_dir() : $tmp_base . 'dompdf';
192
+ break;
193
+ case 'DOMPDF_FONT_DIR': // NEEDS TRAILING SLASH!
194
+ // original value : DOMPDF_DIR."/lib/fonts/"
195
+ // 1.5+ : $tmp_base . 'fonts/'
196
+ $tmp_path = $old_tmp ? DOMPDF_DIR."/lib/fonts/" : $tmp_base . 'fonts/';
197
+ break;
198
+ case 'DOMPDF_FONT_CACHE':
199
+ // original value : DOMPDF_FONT_DIR
200
+ // 1.5+ : $tmp_base . 'fonts'
201
+ $tmp_path = $old_tmp ? DOMPDF_FONT_DIR : $tmp_base . 'fonts';
202
+ break;
203
+ case 'attachments':
204
+ // original value : WooCommerce_PDF_Invoices::$plugin_path . 'tmp/'
205
+ // 1.5+ : $tmp_base . 'attachments/'
206
+ $tmp_path = $old_tmp ? WooCommerce_PDF_Invoices::$plugin_path . 'tmp/' : $tmp_base . 'attachments/';
207
+ break;
208
+ default:
209
+ $tmp_path = $tmp_base . $type;
210
+ break;
211
+ }
212
+
213
+ // double check for existence, in case tmp_base was installed, but subfolder not created
214
+ if ( !@is_dir( $tmp_path ) ) {
215
+ @mkdir( $tmp_path );
216
+ }
217
+
218
+ return $tmp_path;
219
+ }
220
+
221
+ /**
222
+ * return the base tmp folder (usually uploads)
223
+ */
224
+ public function get_tmp_base () {
225
+ // wp_upload_dir() is used to set the base temp folder, under which a
226
+ // 'wpo_wcpdf' folder and several subfolders are created
227
+ //
228
+ // wp_upload_dir() will:
229
+ // * default to WP_CONTENT_DIR/uploads
230
+ // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
231
+ //
232
+ // May also be overridden by the wpo_wcpdf_tmp_path filter
233
+
234
+ $upload_dir = wp_upload_dir();
235
+ $upload_base = trailingslashit( $upload_dir['basedir'] );
236
+ $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
237
+ return $tmp_base;
238
+ }
239
+
240
+ /**
241
+ * Generate the template output
242
+ */
243
+ public function process_template( $template_type, $order_ids ) {
244
+ $this->template_type = $template_type;
245
+ $order_ids = apply_filters( 'wpo_wcpdf_process_order_ids', $order_ids, $template_type );
246
+
247
+ // custom function fix
248
+ if (function_exists('wpo_wcpdf_payment_form')) {
249
+ return false;
250
+ }
251
+
252
+ // filter out trashed orders
253
+ foreach ($order_ids as $key => $order_id) {
254
+ $order_status = get_post_status( $order_id );
255
+ if ( $order_status == 'trash' ) {
256
+ unset( $order_ids[ $key ] );
257
+ }
258
+ }
259
+ // sharing is caring!
260
+ $this->order_ids = $order_ids;
261
+
262
+ // throw error when no order ids
263
+ if ( empty( $order_ids ) ) {
264
+ throw new Exception('No orders to export!');
265
+ }
266
+
267
+ do_action( 'wpo_wcpdf_process_template', $template_type );
268
+
269
+ $output_html = array();
270
+ foreach ($order_ids as $order_id) {
271
+ $this->order = new WC_Order( $order_id );
272
+ do_action( 'wpo_wcpdf_process_template_order', $template_type, $order_id );
273
+
274
+ $template = $this->template_path . '/' . $template_type . '.php';
275
+ $template = apply_filters( 'wpo_wcpdf_template_file', $template, $template_type, $this->order );
276
+
277
+ if (!file_exists($template)) {
278
+ throw new Exception('Template not found! Check if the following file exists: <pre>'.$template.'</pre><br/>');
279
+ }
280
+
281
+ // Set the invoice number
282
+ if ( $template_type == 'invoice' ) {
283
+ $this->set_invoice_number( $order_id );
284
+ }
285
+
286
+ $output_html[$order_id] = $this->get_template($template);
287
+
288
+ // store meta to be able to check if an invoice for an order has been created already
289
+ if ( $template_type == 'invoice' ) {
290
+ update_post_meta( $order_id, '_wcpdf_invoice_exists', 1 );
291
+ }
292
+
293
+
294
+ // Wipe post from cache
295
+ wp_cache_delete( $order_id, 'posts' );
296
+ wp_cache_delete( $order_id, 'post_meta' );
297
+ }
298
+
299
+ $print_script = "<script language=javascript>window.onload = function(){ window.print(); };</script>";
300
+ // <div style="page-break-before: always;"></div>
301
+ $page_break = "\n<div style=\"page-break-before: always;\"></div>\n";
302
+
303
+
304
+ if (apply_filters('wpo_wcpdf_output_html', false, $template_type) && apply_filters('wpo_wcpdf_print_html', false, $template_type)) {
305
+ $this->output_body = $print_script . implode($page_break, $output_html);
306
+ } else {
307
+ $this->output_body = implode($page_break, $output_html);
308
+ }
309
+
310
+ // Try to clean up a bit of memory
311
+ unset($output_html);
312
+
313
+ $template_wrapper = $this->template_path . '/html-document-wrapper.php';
314
+
315
+ if (!file_exists($template_wrapper)) {
316
+ throw new Exception('Template wrapper not found! Check if the following file exists: <pre>'.$template_wrapper.'</pre><br/>');
317
+ }
318
+
319
+ $complete_document = $this->get_template($template_wrapper);
320
+
321
+ // Try to clean up a bit of memory
322
+ unset($this->output_body);
323
+
324
+ // clean up special characters
325
+ $complete_document = utf8_decode(mb_convert_encoding($complete_document, 'HTML-ENTITIES', 'UTF-8'));
326
+
327
+
328
+ return $complete_document;
329
+ }
330
+
331
+ /**
332
+ * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
333
+ */
334
+ public function clear_page_number_styles ( $html, $template_type, $order_ids ) {
335
+ $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">{{PAGE_COUNT}}</span>', $html);
336
+ $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
337
+ return $html;
338
+ }
339
+
340
+ /**
341
+ * Replace {{PAGE_COUNT}} placeholder with total page count
342
+ */
343
+ public function page_number_replacements ( $dompdf, $html, $template_type, $order_ids ) {
344
+ $placeholder = '{{PAGE_COUNT}}';
345
+
346
+ // check if placeholder is used
347
+ if (strpos($html, $placeholder) !== false ) {
348
+ foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
349
+ if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false) {
350
+ $object["c"] = str_replace( $placeholder , $dompdf->get_canvas()->get_page_count() , $object["c"] );
351
+ }
352
+ }
353
+ }
354
+
355
+ return $dompdf;
356
+ }
357
+
358
+ /**
359
+ * Create & render DOMPDF object
360
+ */
361
+ public function generate_pdf( $template_type, $order_ids ) {
362
+ $paper_size = apply_filters( 'wpo_wcpdf_paper_format', $this->template_settings['paper_size'], $template_type );
363
+ $paper_orientation = apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $template_type);
364
+
365
+ do_action( 'wpo_wcpdf_before_pdf', $template_type );
366
+ if ( !class_exists('DOMPDF') ) {
367
+ // extra check to avoid clashes with other plugins using DOMPDF
368
+ // This could have unwanted side-effects when the version that's already
369
+ // loaded is different, and it could also miss fonts etc, but it's better
370
+ // than not checking...
371
+ require_once( WooCommerce_PDF_Invoices::$plugin_path . "lib/dompdf/dompdf_config.inc.php" );
372
+ }
373
+
374
+ $dompdf = new DOMPDF();
375
+ $html = apply_filters( 'wpo_wcpdf_processed_template_html', $this->process_template( $template_type, $order_ids ), $template_type, $order_ids );
376
+ $dompdf->load_html( $html );
377
+ $dompdf->set_paper( $paper_size, $paper_orientation );
378
+ $dompdf = apply_filters( 'wpo_wcpdf_before_dompdf_render', $dompdf, $html, $template_type, $order_ids );
379
+ $dompdf->render();
380
+ $dompdf = apply_filters( 'wpo_wcpdf_after_dompdf_render', $dompdf, $html, $template_type, $order_ids );
381
+ do_action( 'wpo_wcpdf_after_pdf', $template_type );
382
+
383
+ // Try to clean up a bit of memory
384
+ unset($complete_pdf);
385
+
386
+ return $dompdf;
387
+ }
388
+
389
+ /**
390
+ * Stream PDF
391
+ */
392
+ public function stream_pdf( $template_type, $order_ids, $filename ) {
393
+ $dompdf = $this->generate_pdf( $template_type, $order_ids );
394
+ $dompdf->stream($filename);
395
+ }
396
+
397
+ /**
398
+ * Get PDF
399
+ */
400
+ public function get_pdf( $template_type, $order_ids ) {
401
+ try {
402
+ $dompdf = $this->generate_pdf( $template_type, $order_ids );
403
+ return $dompdf->output();
404
+ } catch (Exception $e) {
405
+ echo $e->getMessage();
406
+ return false;
407
+ }
408
+
409
+ }
410
+
411
+ /**
412
+ * Load and generate the template output with ajax
413
+ */
414
+ public function generate_pdf_ajax() {
415
+ // Check the nonce
416
+ if( empty( $_GET['action'] ) || ! is_user_logged_in() || !check_admin_referer( $_GET['action'] ) ) {
417
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
418
+ }
419
+
420
+ // Check if all parameters are set
421
+ if( empty( $_GET['template_type'] ) || empty( $_GET['order_ids'] ) ) {
422
+ wp_die( __( 'Some of the export parameters are missing.', 'wpo_wcpdf' ) );
423
+ }
424
+
425
+ $order_ids = (array) explode('x',$_GET['order_ids']);
426
+ // Process oldest first: reverse $order_ids array
427
+ $order_ids = array_reverse($order_ids);
428
+
429
+ // Check the user privileges
430
+ 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 ) ) {
431
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
432
+ }
433
+
434
+ // User call from my-account page
435
+ if ( isset( $_GET['my-account'] ) ) {
436
+ // Only for single orders!
437
+ if ( count( $order_ids ) > 1 ) {
438
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
439
+ }
440
+
441
+ // Get user_id of order
442
+ $this->order = new WC_Order ( $order_ids[0] );
443
+
444
+ // Check if current user is owner of order IMPORTANT!!!
445
+ if ( $this->order->user_id != get_current_user_id() ) {
446
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpo_wcpdf' ) );
447
+ }
448
+
449
+ // if we got here, we're safe to go!
450
+ }
451
+
452
+ // Generate the output
453
+ $template_type = $_GET['template_type'];
454
+ // die($this->process_template( $template_type, $order_ids )); // or use the filter switch below!
455
+
456
+ if (apply_filters('wpo_wcpdf_output_html', false, $template_type)) {
457
+ // Output html to browser for debug
458
+ // NOTE! images will be loaded with the server path by default
459
+ // use the wpo_wcpdf_use_path filter (return false) to change this to http urls
460
+ die($this->process_template( $template_type, $order_ids ));
461
+ }
462
+
463
+ if ( !($pdf = $this->get_pdf( $template_type, $order_ids )) ) {
464
+ exit;
465
+ }
466
+
467
+ $filename = $this->build_filename( $template_type, $order_ids, 'download' );
468
+
469
+ do_action( 'wpo_wcpdf_created_manually', $pdf, $filename );
470
+
471
+ // Get output setting
472
+ $output_mode = isset($this->general_settings['download_display'])?$this->general_settings['download_display']:'';
473
+
474
+ // Switch headers according to output setting
475
+ if ( $output_mode == 'display' || empty($output_mode) ) {
476
+ header('Content-type: application/pdf');
477
+ header('Content-Disposition: inline; filename="'.$filename.'"');
478
+ } else {
479
+ header('Content-Description: File Transfer');
480
+ header('Content-Type: application/octet-stream');
481
+ header('Content-Disposition: attachment; filename="'.$filename.'"');
482
+ header('Content-Transfer-Encoding: binary');
483
+ header('Connection: Keep-Alive');
484
+ header('Expires: 0');
485
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
486
+ header('Pragma: public');
487
+ }
488
+
489
+ // output PDF data
490
+ echo($pdf);
491
+
492
+ exit;
493
+ }
494
+
495
+ /**
496
+ * Build filename
497
+ */
498
+ public function build_filename( $template_type, $order_ids, $context ) {
499
+ $count = count($order_ids);
500
+
501
+ switch ($template_type) {
502
+ case 'invoice':
503
+ $name = _n( 'invoice', 'invoices', $count, 'wpo_wcpdf' );
504
+ $number = $this->get_display_number( $order_ids[0] );
505
+ break;
506
+ case 'packing-slip':
507
+ $name = _n( 'packing-slip', 'packing-slips', $count, 'wpo_wcpdf' );
508
+ $number = $this->order->get_order_number();
509
+ break;
510
+ default:
511
+ $name = $template_type;
512
+ $number = $this->order->get_order_number();
513
+ break;
514
+ }
515
+
516
+ if ( $count == 1 ) {
517
+ $suffix = $number;
518
+ } else {
519
+ $suffix = date('Y-m-d'); // 2020-11-11
520
+ }
521
+
522
+ $filename = $name . '-' . $suffix . '.pdf';
523
+
524
+ // Filter depending on context (for legacy filter support)
525
+ if ( $context == 'download' ) {
526
+ $filename = apply_filters( 'wpo_wcpdf_bulk_filename', $filename, $order_ids, $name, $template_type );
527
+ } elseif ( $context == 'attachment' ) {
528
+ $filename = apply_filters( 'wpo_wcpdf_attachment_filename', $filename, $number, $order_ids[0] );
529
+ }
530
+
531
+ // Filter filename (use this filter instead of the above legacy filters!)
532
+ $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $template_type, $order_ids, $context );
533
+
534
+ // sanitize filename (after filters to prevent human errors)!
535
+ return sanitize_file_name( $filename );
536
+ }
537
+
538
+ /**
539
+ * Attach invoice to completed order or customer invoice email
540
+ */
541
+ public function attach_pdf_to_email ( $attachments, $status, $order ) {
542
+ // check if all variables properly set
543
+ if ( !is_object( $order ) || !isset( $status ) ) {
544
+ return $attachments;
545
+ }
546
+
547
+ // Skip User emails
548
+ if ( get_class( $order ) == 'WP_User' ) {
549
+ return $attachments;
550
+ }
551
+
552
+ // WooCommerce Booking compatibility
553
+ if ( get_post_type( $order->id ) == 'wc_booking' && isset($order->order) ) {
554
+ // $order is actually a WC_Booking object!
555
+ $order = $order->order;
556
+ }
557
+
558
+ // do not process low stock notifications, user emails etc!
559
+ if ( in_array( $status, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order->id ) != 'shop_order' ) {
560
+ return $attachments;
561
+ }
562
+
563
+ // Disable free setting check
564
+ $order_total = $order->get_total();
565
+ if ( $order_total == 0 && isset($this->general_settings['disable_free']) ) {
566
+ return $attachments;
567
+ }
568
+
569
+ $this->order = $order;
570
+
571
+ $tmp_path = $this->tmp_path('attachments');
572
+
573
+ // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
574
+ array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
575
+
576
+ // set allowed statuses for invoices
577
+ $invoice_allowed = isset($this->general_settings['email_pdf']) ? array_keys( $this->general_settings['email_pdf'] ) : array();
578
+ $documents = array(
579
+ 'invoice' => apply_filters( 'wpo_wcpdf_email_allowed_statuses', $invoice_allowed ), // Relevant (default) statuses: new_order, customer_invoice, customer_processing_order, customer_completed_order
580
+ );
581
+ $documents = apply_filters('wpo_wcpdf_attach_documents', $documents );
582
+
583
+ foreach ($documents as $template_type => $allowed_statuses ) {
584
+ // convert 'lazy' status name
585
+ foreach ($allowed_statuses as $key => $order_status) {
586
+ if ($order_status == 'completed' || $order_status == 'processing') {
587
+ $allowed_statuses[$key] = "customer_" . $order_status . "_order";
588
+ }
589
+ }
590
+
591
+ // legacy filter, use wpo_wcpdf_custom_attachment_condition instead!
592
+ $attach_invoice = apply_filters('wpo_wcpdf_custom_email_condition', true, $order, $status );
593
+ if ( $template_type == 'invoice' && !$attach_invoice ) {
594
+ // don't attach invoice, continue with other documents
595
+ continue;
596
+ }
597
+
598
+ // use this filter to add an extra condition - return false to disable the PDF attachment
599
+ $attach_document = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $status, $template_type );
600
+ if( in_array( $status, $allowed_statuses ) && $attach_document ) {
601
+ // create pdf data
602
+ $pdf_data = $this->get_pdf( $template_type, (array) $order->id );
603
+
604
+ if ( !$pdf_data ) {
605
+ // something went wrong, continue trying with other documents
606
+ continue;
607
+ }
608
+
609
+ // compose filename
610
+ $pdf_filename = $this->build_filename( $template_type, (array) $order->id, 'attachment' );
611
+
612
+ $pdf_path = $tmp_path . $pdf_filename;
613
+ file_put_contents ( $pdf_path, $pdf_data );
614
+ $attachments[] = $pdf_path;
615
+
616
+ do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $template_type );
617
+ }
618
+ }
619
+
620
+ return $attachments;
621
+ }
622
+
623
+ public function set_invoice_number( $order_id ) {
624
+ // first check: get invoice number from post meta
625
+ $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true );
626
+
627
+ // add invoice number if it doesn't exist
628
+ if ( empty($invoice_number) || !isset($invoice_number) ) {
629
+ global $wpdb;
630
+ // making direct DB call to avoid caching issues
631
+ $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' ) );
632
+ $next_invoice_number = apply_filters( 'wpo_wcpdf_next_invoice_number', $next_invoice_number, $order_id );
633
+
634
+ if ( empty($next_invoice_number) ) {
635
+ // First time! We start numbering from order_number or order_id
636
+
637
+ // Check if $order_number is an integer
638
+ $order_number = ltrim($this->order->get_order_number(), '#');
639
+ if ( ctype_digit( (string)$order_number ) ) {
640
+ // order_number == integer: use as starting point.
641
+ $invoice_number = $order_number;
642
+ } else {
643
+ // fallback: use order_id as starting point.
644
+ $invoice_number = $order_id;
645
+ }
646
+
647
+ } else {
648
+ $invoice_number = $next_invoice_number;
649
+ }
650
+
651
+ // reset invoice number yearly
652
+ if ( isset( $this->template_settings['yearly_reset_invoice_number'] ) ) {
653
+ $current_year = date("Y");
654
+ $last_invoice_year = get_option( 'wpo_wcpdf_last_invoice_year' );
655
+ // check first time use
656
+ if ( empty( $last_invoice_year ) ) {
657
+ $last_invoice_year = $current_year;
658
+ update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
659
+ }
660
+ // check if we need to reset
661
+ if ( $current_year != $last_invoice_year ) {
662
+ $invoice_number = 1;
663
+ update_option( 'wpo_wcpdf_last_invoice_year', $current_year );
664
+ }
665
+ }
666
+ // die($invoice_number);
667
+
668
+ // invoice number logging
669
+ // $order_number = ltrim($this->order->get_order_number(), '#');
670
+ // $this->log( $order_id, "Invoice number {$invoice_number} set for order {$order_number} (id {$order_id})" );
671
+
672
+ update_post_meta($order_id, '_wcpdf_invoice_number', $invoice_number);
673
+ update_post_meta($order_id, '_wcpdf_formatted_invoice_number', $this->get_invoice_number( $order_id ) );
674
+
675
+ // increase next_order_number
676
+ $update_args = array(
677
+ 'option_value' => $invoice_number + 1,
678
+ 'autoload' => 'yes',
679
+ );
680
+ $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => 'wpo_wcpdf_next_invoice_number' ) );
681
+ }
682
+
683
+ // store invoice_number in class object
684
+ $this->invoice_number = $invoice_number;
685
+
686
+ // store invoice number in _POST superglobal to prevent the number from being cleared in a save action
687
+ // (http://wordpress.org/support/topic/customer-invoice-selection-from-order-detail-page-doesnt-record-invoice-id?replies=1)
688
+ $_POST['_wcpdf_invoice_number'] = $invoice_number;
689
+
690
+ return $invoice_number;
691
+ }
692
+
693
+ public function get_invoice_number( $order_id ) {
694
+ // get invoice number from post meta
695
+ if ( $invoice_number = get_post_meta( $order_id, '_wcpdf_invoice_number', true ) ) {
696
+ // check if we have already loaded this order
697
+ if ( $this->order->id == $order_id ) {
698
+ $order_number = $this->order->get_order_number();
699
+ $order_date = $this->order->order_date;
700
+ } else {
701
+ $order = new WC_Order( $order_id );
702
+ $order_number = $order->get_order_number();
703
+ $order_date = $order->order_date;
704
+ }
705
+
706
+ return apply_filters( 'wpo_wcpdf_invoice_number', $invoice_number, $order_number, $order_id, $order_date );
707
+ } else {
708
+ // no invoice number for this order
709
+ return false;
710
+ }
711
+ }
712
+
713
+ /**
714
+ * Add invoice number to WC REST API
715
+ */
716
+ public function woocommerce_api_invoice_numer ( $data, $order ) {
717
+ if ( $invoice_number = $this->get_invoice_number( $order->id ) ) {
718
+ $data['wpo_wcpdf_invoice_number'] = $invoice_number;
719
+ } else {
720
+ $data['wpo_wcpdf_invoice_number'] = '';
721
+ }
722
+ return $data;
723
+ }
724
+
725
+ /**
726
+ * Reset invoice data for WooCommerce subscription renewal orders
727
+ * https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
728
+ */
729
+ public function woocommerce_subscriptions_renewal_order_created ( $renewal_order, $original_order, $product_id, $new_order_role ) {
730
+ $this->reset_invoice_data( $renewal_order->id );
731
+ return $renewal_order;
732
+ }
733
+
734
+ public function wcs_renewal_order_created ( $renewal_order, $subscription ) {
735
+ $this->reset_invoice_data( $renewal_order->id );
736
+ return $renewal_order;
737
+ }
738
+
739
+ public function reset_invoice_data ( $order_id ) {
740
+ // delete invoice number, invoice date & invoice exists meta
741
+ delete_post_meta( $order_id, '_wcpdf_invoice_number' );
742
+ delete_post_meta( $order_id, '_wcpdf_formatted_invoice_number' );
743
+ delete_post_meta( $order_id, '_wcpdf_invoice_date' );
744
+ delete_post_meta( $order_id, '_wcpdf_invoice_exists' );
745
+ }
746
+
747
+ public function format_invoice_number( $invoice_number, $order_number, $order_id, $order_date ) {
748
+ // get format settings
749
+ $formats['prefix'] = isset($this->template_settings['invoice_number_formatting_prefix'])?$this->template_settings['invoice_number_formatting_prefix']:'';
750
+ $formats['suffix'] = isset($this->template_settings['invoice_number_formatting_suffix'])?$this->template_settings['invoice_number_formatting_suffix']:'';
751
+ $formats['padding'] = isset($this->template_settings['invoice_number_formatting_padding'])?$this->template_settings['invoice_number_formatting_padding']:'';
752
+
753
+ // Replacements
754
+ $order_year = date_i18n( 'Y', strtotime( $order_date ) );
755
+ $order_month = date_i18n( 'm', strtotime( $order_date ) );
756
+ $order_day = date_i18n( 'd', strtotime( $order_date ) );
757
+ $invoice_date = get_post_meta($order_id,'_wcpdf_invoice_date',true);
758
+ $invoice_date = empty($invoice_date) ? current_time('mysql') : $invoice_date;
759
+ $invoice_year = date_i18n( 'Y', strtotime( $invoice_date ) );
760
+ $invoice_month = date_i18n( 'm', strtotime( $invoice_date ) );
761
+ $invoice_day = date_i18n( 'd', strtotime( $invoice_date ) );
762
+
763
+ foreach ($formats as $key => $value) {
764
+ $value = str_replace('[order_year]', $order_year, $value);
765
+ $value = str_replace('[order_month]', $order_month, $value);
766
+ $value = str_replace('[order_day]', $order_day, $value);
767
+ $value = str_replace('[invoice_year]', $invoice_year, $value);
768
+ $value = str_replace('[invoice_month]', $invoice_month, $value);
769
+ $value = str_replace('[invoice_day]', $invoice_day, $value);
770
+ $formats[$key] = $value;
771
+ }
772
+
773
+ // Padding
774
+ if ( ctype_digit( (string)$formats['padding'] ) ) {
775
+ $invoice_number = sprintf('%0'.$formats['padding'].'d', $invoice_number);
776
+ }
777
+
778
+ $formatted_invoice_number = $formats['prefix'] . $invoice_number . $formats['suffix'] ;
779
+
780
+ return $formatted_invoice_number;
781
+ }
782
+
783
+ public function get_display_number( $order_id ) {
784
+ if ( !isset($this->order->id) ) {
785
+ $this->order = new WC_Order ( $order_id );
786
+ }
787
+
788
+ if ( isset($this->template_settings['display_number']) && $this->template_settings['display_number'] == 'invoice_number' ) {
789
+ // use invoice number
790
+ $display_number = $this->get_invoice_number( $order_id );
791
+ // die($display_number);
792
+ } else {
793
+ // use order number
794
+ $display_number = ltrim($this->order->get_order_number(), '#');
795
+ }
796
+
797
+ return $display_number;
798
+ }
799
+
800
+ /**
801
+ * Return evaluated template contents
802
+ */
803
+ public function get_template( $file ) {
804
+ ob_start();
805
+ if (file_exists($file)) {
806
+ include($file);
807
+ }
808
+ return ob_get_clean();
809
+ }
810
+
811
+ /**
812
+ * Get the current order
813
+ */
814
+ public function get_order() {
815
+ return $this->order;
816
+ }
817
+
818
+ /**
819
+ * Get the current order items
820
+ */
821
+ public function get_order_items() {
822
+ global $woocommerce;
823
+ global $_product;
824
+
825
+ $items = $this->order->get_items();
826
+ $data_list = array();
827
+
828
+ if( sizeof( $items ) > 0 ) {
829
+ foreach ( $items as $item_id => $item ) {
830
+ // Array with data for the pdf template
831
+ $data = array();
832
+
833
+ // Set the item_id
834
+ $data['item_id'] = $item_id;
835
+
836
+ // Set the id
837
+ $data['product_id'] = $item['product_id'];
838
+ $data['variation_id'] = $item['variation_id'];
839
+
840
+ // Set item name
841
+ $data['name'] = $item['name'];
842
+
843
+ // Set item quantity
844
+ $data['quantity'] = $item['qty'];
845
+
846
+ // Set the line total (=after discount)
847
+ $data['line_total'] = $this->wc_price( $item['line_total'] );
848
+ $data['single_line_total'] = $this->wc_price( $item['line_total'] / max( 1, $item['qty'] ) );
849
+ $data['line_tax'] = $this->wc_price( $item['line_tax'] );
850
+ $data['single_line_tax'] = $this->wc_price( $item['line_tax'] / max( 1, $item['qty'] ) );
851
+
852
+ $line_tax_data = maybe_unserialize( isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '' );
853
+ $data['tax_rates'] = $this->get_tax_rate( $item['tax_class'], $item['line_total'], $item['line_tax'], $line_tax_data );
854
+
855
+ // Set the line subtotal (=before discount)
856
+ $data['line_subtotal'] = $this->wc_price( $item['line_subtotal'] );
857
+ $data['line_subtotal_tax'] = $this->wc_price( $item['line_subtotal_tax'] );
858
+ $data['ex_price'] = $this->get_formatted_item_price ( $item, 'total', 'excl' );
859
+ $data['price'] = $this->get_formatted_item_price ( $item, 'total' );
860
+ $data['order_price'] = $this->order->get_formatted_line_subtotal( $item ); // formatted according to WC settings
861
+
862
+ // Calculate the single price with the same rules as the formatted line subtotal (!)
863
+ // = before discount
864
+ $data['ex_single_price'] = $this->get_formatted_item_price ( $item, 'single', 'excl' );
865
+ $data['single_price'] = $this->get_formatted_item_price ( $item, 'single' );
866
+
867
+ // Pass complete item array
868
+ $data['item'] = $item;
869
+
870
+ // Create the product to display more info
871
+ $data['product'] = null;
872
+
873
+ $product = $this->order->get_product_from_item( $item );
874
+
875
+ // Checking fo existance, thanks to MDesigner0
876
+ if(!empty($product)) {
877
+ // Set the thumbnail id DEPRICATED (does not support thumbnail sizes), use thumbnail_path or thumbnail instead
878
+ $data['thumbnail_id'] = $this->get_thumbnail_id( $product );
879
+
880
+ // Thumbnail (full img tag)
881
+ $data['thumbnail'] = $this->get_thumbnail ( $product );
882
+
883
+ // Set the single price (turned off to use more consistent calculated price)
884
+ // $data['single_price'] = woocommerce_price ( $product->get_price() );
885
+
886
+ // Set item SKU
887
+ $data['sku'] = $product->get_sku();
888
+
889
+ // Set item weight
890
+ $data['weight'] = $product->get_weight();
891
+
892
+ // Set item dimensions
893
+ $data['dimensions'] = $product->get_dimensions();
894
+
895
+ // Pass complete product object
896
+ $data['product'] = $product;
897
+
898
+ }
899
+
900
+ // Set item meta
901
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
902
+ $meta = new WC_Order_Item_Meta( $item['item_meta'], $product );
903
+ } else {
904
+ // pass complete item for WC2.4+
905
+ $meta = new WC_Order_Item_Meta( $item, $product );
906
+ }
907
+
908
+ $data['meta'] = $meta->display( false, true );
909
+
910
+ $data_list[$item_id] = apply_filters( 'wpo_wcpdf_order_item_data', $data, $this->order );
911
+ }
912
+ }
913
+
914
+ return apply_filters( 'wpo_wcpdf_order_items_data', $data_list, $this->order );
915
+ }
916
+
917
+ /**
918
+ * Gets price - formatted for display.
919
+ *
920
+ * @access public
921
+ * @param mixed $item
922
+ * @return string
923
+ */
924
+ public function get_formatted_item_price ( $item, $type, $tax_display = '' ) {
925
+ $item_price = 0;
926
+ $divider = ($type == 'single' && $item['qty'] != 0 )?$item['qty']:1; //divide by 1 if $type is not 'single' (thus 'total')
927
+
928
+ if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) )
929
+ return;
930
+
931
+ if ( $tax_display == 'excl' ) {
932
+ $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item )) / $divider );
933
+ } else {
934
+ $item_price = $this->wc_price( ($this->order->get_line_subtotal( $item, true )) / $divider );
935
+ }
936
+
937
+ return $item_price;
938
+ }
939
+
940
+ /**
941
+ * wrapper for wc2.1 depricated price function
942
+ */
943
+ public function wc_price( $price, $args = array() ) {
944
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
945
+ // WC 2.1 or newer is used
946
+ $args['currency'] = $this->order->get_order_currency();
947
+ $formatted_price = wc_price( $price, $args );
948
+ } else {
949
+ $formatted_price = woocommerce_price( $price );
950
+ }
951
+
952
+ return $formatted_price;
953
+ }
954
+
955
+ /**
956
+ * Get the tax rates/percentages for a given tax class
957
+ * @param string $tax_class tax class slug
958
+ * @return string $tax_rates imploded list of tax rates
959
+ */
960
+ public function get_tax_rate( $tax_class, $line_total, $line_tax, $line_tax_data = '' ) {
961
+ if ( $line_tax == 0 ) {
962
+ return '-'; // no need to determine tax rate...
963
+ }
964
+
965
+ // first try the easy wc2.2 way, using line_tax_data
966
+ if ( !empty( $line_tax_data ) && isset($line_tax_data['total']) ) {
967
+ $tax_rates = array();
968
+
969
+ $line_taxes = $line_tax_data['total'];
970
+ foreach ( $line_taxes as $tax_id => $tax ) {
971
+ if ( !empty($tax) && $tax != 0 ) {
972
+ $tax_rates[] = $this->get_tax_rate_by_id( $tax_id ) . ' %';
973
+ }
974
+ }
975
+
976
+ $tax_rates = implode(' ,', $tax_rates );
977
+ return $tax_rates;
978
+ }
979
+
980
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 && !apply_filters( 'wpo_wcpdf_calculate_tax_rate', false ) ) {
981
+ // WC 2.1 or newer is used
982
+
983
+ // if (empty($tax_class))
984
+ // $tax_class = 'standard';// does not appear to work anymore - get_rates does accept an empty tax_class though!
985
+
986
+ $tax = new WC_Tax();
987
+ $taxes = $tax->get_rates( $tax_class );
988
+
989
+ $tax_rates = array();
990
+
991
+ foreach ($taxes as $tax) {
992
+ $tax_rates[$tax['label']] = round( $tax['rate'], 2 ).' %';
993
+ }
994
+
995
+ if (empty($tax_rates)) {
996
+ // one last try: manually calculate
997
+ if ( $line_total != 0) {
998
+ $tax_rates[] = round( ($line_tax / $line_total)*100, 1 ).' %';
999
+ } else {
1000
+ $tax_rates[] = '-';
1001
+ }
1002
+ }
1003
+
1004
+ $tax_rates = implode(' ,', $tax_rates );
1005
+ } else {
1006
+ // Backwards compatibility/fallback: calculate tax from line items
1007
+ if ( $line_total != 0) {
1008
+ $tax_rates = round( ($line_tax / $line_total)*100, 1 ).' %';
1009
+ } else {
1010
+ $tax_rates = '-';
1011
+ }
1012
+ }
1013
+
1014
+ return $tax_rates;
1015
+ }
1016
+
1017
+ /**
1018
+ * Returns the percentage rate (float) for a given tax rate ID.
1019
+ * @param int $rate_id woocommerce tax rate id
1020
+ * @return float $rate percentage rate
1021
+ */
1022
+ public function get_tax_rate_by_id( $rate_id ) {
1023
+ global $wpdb;
1024
+ $rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) );
1025
+ return (float) $rate;
1026
+ }
1027
+
1028
+ /**
1029
+ * Returns a an array with rate_id => tax rate data (array) of all tax rates in woocommerce
1030
+ * @return array $tax_rate_ids keyed by id
1031
+ */
1032
+ public function get_tax_rate_ids() {
1033
+ global $wpdb;
1034
+ $rates = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates" );
1035
+
1036
+ $tax_rate_ids = array();
1037
+ foreach ($rates as $rate) {
1038
+ // var_dump($rate->tax_rate_id);
1039
+ // die($rate);
1040
+ $rate_id = $rate->tax_rate_id;
1041
+ unset($rate->tax_rate_id);
1042
+ $tax_rate_ids[$rate_id] = (array) $rate;
1043
+ }
1044
+
1045
+ return $tax_rate_ids;
1046
+ }
1047
+
1048
+ /**
1049
+ * Get order custom field
1050
+ */
1051
+ public function get_order_field( $field ) {
1052
+ if( isset( $this->get_order()->order_custom_fields[$field] ) ) {
1053
+ return $this->get_order()->order_custom_fields[$field][0];
1054
+ }
1055
+ return;
1056
+ }
1057
+
1058
+ /**
1059
+ * Returns the main product image ID
1060
+ * Adapted from the WC_Product class
1061
+ *
1062
+ * @access public
1063
+ * @return string
1064
+ */
1065
+ public function get_thumbnail_id ( $product ) {
1066
+ // DEPRICATED (does not support thumbnail sizes)
1067
+ global $woocommerce;
1068
+
1069
+ if ( $product->variation_id && has_post_thumbnail( $product->variation_id ) ) {
1070
+ $thumbnail_id = get_post_thumbnail_id ( $product->variation_id );
1071
+ } elseif ( has_post_thumbnail( $product->id ) ) {
1072
+ $thumbnail_id = get_post_thumbnail_id ( $product->id );
1073
+ } elseif ( ( $parent_id = wp_get_post_parent_id( $product->id ) ) && has_post_thumbnail( $parent_id ) ) {
1074
+ $thumbnail_id = get_post_thumbnail_id ( $parent_id );
1075
+ } else {
1076
+ $thumbnail_id = $woocommerce->plugin_url() . '/assets/images/placeholder.png';
1077
+ }
1078
+
1079
+ return $thumbnail_id;
1080
+ }
1081
+
1082
+ public function get_thumbnail ( $product ) {
1083
+ // Get default WooCommerce img tag (url/http)
1084
+ $size = apply_filters( 'wpo_wcpdf_thumbnail_size', 'shop_thumbnail' );
1085
+ $thumbnail_img_tag_url = $product->get_image( $size, array( 'title' => '' ) );
1086
+
1087
+ // Extract the url from img
1088
+ preg_match('/<img(.*)src(.*)=(.*)"(.*)"/U', $thumbnail_img_tag_url, $thumbnail_url );
1089
+ // convert url to path
1090
+ $thumbnail_path = str_replace( get_site_url() . '/', ABSPATH, array_pop($thumbnail_url));
1091
+
1092
+ // Thumbnail (full img tag)
1093
+ if (apply_filters('wpo_wcpdf_use_path', true) && file_exists($thumbnail_path)) {
1094
+ // load img with server path by default
1095
+ $thumbnail = sprintf('<img width="90" height="90" src="%s" class="attachment-shop_thumbnail wp-post-image">', $thumbnail_path );
1096
+ } else {
1097
+ // load img with http url when filtered
1098
+ $thumbnail = $thumbnail_img_tag_url;
1099
+ }
1100
+
1101
+ // die($thumbnail);
1102
+
1103
+ return $thumbnail;
1104
+ }
1105
+
1106
+ public function add_product_bundles_classes ( $classes, $template_type, $order, $item_id = '' ) {
1107
+ if ( empty($item_id) ) {
1108
+ // get item id from classes (backwards compatibility fix)
1109
+ $class_array = explode(' ', $classes);
1110
+ foreach ($class_array as $class) {
1111
+ if (is_numeric($class)) {
1112
+ $item_id = $class;
1113
+ break;
1114
+ }
1115
+ }
1116
+
1117
+ // if still empty, we lost the item id somewhere :(
1118
+ if (empty($item_id)) {
1119
+ return $classes;
1120
+ }
1121
+ }
1122
+
1123
+ $item_meta = $order->get_item_meta( $item_id );
1124
+
1125
+ if (isset($item_meta['_bundled_by'])) {
1126
+ $classes = $classes . ' bundled-item';
1127
+
1128
+ // check bundled item visibility
1129
+ if ( ! empty( $item_meta[ '_bundled_item_hidden' ] ) ) {
1130
+ $classes = $classes . ' hidden';
1131
+ }
1132
+
1133
+ return $classes;
1134
+ } elseif (isset($item_meta['_bundled_items'])) {
1135
+ return $classes . ' product-bundle';
1136
+ }
1137
+
1138
+ return $classes;
1139
+ }
1140
+
1141
+ public function add_chained_product_class ( $classes, $template_type, $order, $item_id = '' ) {
1142
+ if ( empty($item_id) ) {
1143
+ // get item id from classes (backwards compatibility fix)
1144
+ $class_array = explode(' ', $classes);
1145
+ foreach ($class_array as $class) {
1146
+ if (is_numeric($class)) {
1147
+ $item_id = $class;
1148
+ break;
1149
+ }
1150
+ }
1151
+
1152
+ // if still empty, we lost the item id somewhere :(
1153
+ if (empty($item_id)) {
1154
+ return $classes;
1155
+ }
1156
+ }
1157
+
1158
+ $item_meta = $order->get_item_meta( $item_id );
1159
+
1160
+ if (isset($item_meta['_chained_product_of'])) {
1161
+ return $classes . ' chained-product';
1162
+ }
1163
+
1164
+ return $classes;
1165
+ }
1166
+
1167
+ /**
1168
+ * Filter plugin strings with qTranslate-X
1169
+ */
1170
+ public function qtranslatex_filters() {
1171
+ $use_filters = array(
1172
+ 'wpo_wcpdf_shop_name' => 20,
1173
+ 'wpo_wcpdf_shop_address' => 20,
1174
+ 'wpo_wcpdf_footer' => 20,
1175
+ 'wpo_wcpdf_order_items' => 20,
1176
+ 'wpo_wcpdf_payment_method' => 20,
1177
+ 'wpo_wcpdf_shipping_method' => 20,
1178
+ 'wpo_wcpdf_extra_1' => 20,
1179
+ 'wpo_wcpdf_extra_2' => 20,
1180
+ 'wpo_wcpdf_extra_3' => 20,
1181
+ );
1182
+
1183
+ foreach ( $use_filters as $name => $priority ) {
1184
+ add_filter( $name, 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage', $priority );
1185
+ }
1186
+ }
1187
+
1188
+ /**
1189
+ * Use currency symbol font (when enabled in options)
1190
+ */
1191
+ public function use_currency_font ( $template_type ) {
1192
+ add_filter( 'woocommerce_currency_symbol', array( $this, 'wrap_currency_symbol' ), 10, 2);
1193
+ add_action( 'wpo_wcpdf_custom_styles', array($this, 'currency_symbol_font_styles' ) );
1194
+ }
1195
+
1196
+ public function wrap_currency_symbol( $currency_symbol, $currency ) {
1197
+ $currency_symbol = sprintf( '<span class="wcpdf-currency-symbol">%s</span>', $currency_symbol );
1198
+ return $currency_symbol;
1199
+ }
1200
+
1201
+ public function currency_symbol_font_styles () {
1202
+ ?>
1203
+ .wcpdf-currency-symbol { font-family: 'Currencies'; }
1204
+ <?php
1205
+ }
1206
+
1207
+ public function enable_debug () {
1208
+ error_reporting( E_ALL );
1209
+ ini_set( 'display_errors', 1 );
1210
+ }
1211
+
1212
+ /**
1213
+ * Log messages
1214
+ */
1215
+
1216
+ public function log( $order_id, $message ) {
1217
+ $current_date_time = date("Y-m-d H:i:s");
1218
+ $message = $order_id . ' ' . $current_date_time .' ' .$message ."\n";
1219
+ $file = $this->tmp_path() . 'log.txt';
1220
+
1221
+ file_put_contents($file, $message, FILE_APPEND);
1222
+ }
1223
+ }
1224
+
1225
+ }
includes/class-wcpdf-settings.php CHANGED
@@ -1,1412 +1,1412 @@
1
- <?php
2
-
3
- /**
4
- * Settings class
5
- */
6
- if ( ! class_exists( 'WooCommerce_PDF_Invoices_Settings' ) ) {
7
-
8
- class WooCommerce_PDF_Invoices_Settings {
9
-
10
- public $options_page_hook;
11
- public $general_settings;
12
- public $template_settings;
13
-
14
- public function __construct() {
15
- add_action( 'admin_menu', array( &$this, 'menu' ) ); // Add menu.
16
- add_action( 'admin_init', array( &$this, 'init_settings' ) ); // Registers settings
17
- add_filter( 'option_page_capability_wpo_wcpdf_template_settings', array( &$this, 'settings_capabilities' ) );
18
- add_filter( 'option_page_capability_wpo_wcpdf_general_settings', array( &$this, 'settings_capabilities' ) );
19
- add_action( 'admin_enqueue_scripts', array( &$this, 'load_scripts_styles' ) ); // Load scripts
20
-
21
- // Add links to WordPress plugins page
22
- add_filter( 'plugin_action_links_'.WooCommerce_PDF_Invoices::$plugin_basename, array( &$this, 'wpo_wcpdf_add_settings_link' ) );
23
- add_filter( 'plugin_row_meta', array( $this, 'add_support_links' ), 10, 2 );
24
-
25
- $this->general_settings = get_option('wpo_wcpdf_general_settings');
26
- $this->template_settings = get_option('wpo_wcpdf_template_settings');
27
-
28
- // WooCommerce Order Status & Actions Manager emails compatibility
29
- add_filter( 'wpo_wcpdf_wc_emails', array( $this, 'wc_order_status_actions_emails' ), 10, 1 );
30
- }
31
-
32
- public function menu() {
33
- $parent_slug = 'woocommerce';
34
-
35
- $this->options_page_hook = add_submenu_page(
36
- $parent_slug,
37
- __( 'PDF Invoices', 'wpo_wcpdf' ),
38
- __( 'PDF Invoices', 'wpo_wcpdf' ),
39
- 'manage_woocommerce',
40
- 'wpo_wcpdf_options_page',
41
- array( $this, 'settings_page' )
42
- );
43
- }
44
-
45
- /**
46
- * Set capability for settings page
47
- */
48
- public function settings_capabilities() {
49
- return 'manage_woocommerce';
50
- }
51
-
52
- /**
53
- * Styles for settings page
54
- */
55
- public function load_scripts_styles ( $hook ) {
56
- if( $hook != $this->options_page_hook )
57
- return;
58
-
59
- wp_enqueue_script(
60
- 'wcpdf-upload-js',
61
- plugins_url( 'js/media-upload.js' , dirname(__FILE__) ),
62
- array( 'jquery' ),
63
- WooCommerce_PDF_Invoices::$version
64
- );
65
-
66
- wp_enqueue_style(
67
- 'wpo-wcpdf',
68
- WooCommerce_PDF_Invoices::$plugin_url . 'css/style.css',
69
- array(),
70
- WooCommerce_PDF_Invoices::$version
71
- );
72
- wp_enqueue_media();
73
- }
74
-
75
- /**
76
- * Add settings link to plugins page
77
- */
78
- public function wpo_wcpdf_add_settings_link( $links ) {
79
- $settings_link = '<a href="admin.php?page=wpo_wcpdf_options_page">'. __( 'Settings', 'woocommerce' ) . '</a>';
80
- array_push( $links, $settings_link );
81
- return $links;
82
- }
83
-
84
- /**
85
- * Add various support links to plugin page
86
- * after meta (version, authors, site)
87
- */
88
- public function add_support_links( $links, $file ) {
89
- if ( !current_user_can( 'install_plugins' ) ) {
90
- return $links;
91
- }
92
-
93
- if ( $file == WooCommerce_PDF_Invoices::$plugin_basename ) {
94
- // $links[] = '<a href="..." target="_blank" title="' . __( '...', 'wpo_wcpdf' ) . '">' . __( '...', 'wpo_wcpdf' ) . '</a>';
95
- }
96
- return $links;
97
- }
98
-
99
- public function settings_page() {
100
- $settings_tabs = apply_filters( 'wpo_wcpdf_settings_tabs', array (
101
- 'general' => __('General','wpo_wcpdf'),
102
- 'template' => __('Template','wpo_wcpdf'),
103
- )
104
- );
105
-
106
- // add status tab last in row
107
- $settings_tabs['debug'] = __('Status','wpo_wcpdf');
108
-
109
- $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'general';
110
-
111
- ?>
112
- <script type="text/javascript">
113
- window.onload = function () {
114
- document.getElementById("footer-thankyou").innerHTML = "If you like <strong>WooCommerce PDF Invoices & Packing Slips</strong> please leave us a <a href='https://wordpress.org/support/view/plugin-reviews/woocommerce-pdf-invoices-packing-slips?rate=5#postform'>★★★★★</a> rating. A huge thank you in advance!";
115
- };
116
- </script>
117
- <div class="wrap">
118
- <div class="icon32" id="icon-options-general"><br /></div>
119
- <h2><?php _e( 'WooCommerce PDF Invoices', 'wpo_wcpdf' ); ?></h2>
120
- <h2 class="nav-tab-wrapper">
121
- <?php
122
- foreach ($settings_tabs as $tab_slug => $tab_title ) {
123
- printf('<a href="?page=wpo_wcpdf_options_page&tab=%1$s" class="nav-tab nav-tab-%1$s %2$s">%3$s</a>', $tab_slug, (($active_tab == $tab_slug) ? 'nav-tab-active' : ''), $tab_title);
124
- }
125
- ?>
126
- </h2>
127
-
128
- <?php
129
- do_action( 'wpo_wcpdf_before_settings_page', $active_tab );
130
-
131
- // save or check option to hide extensions ad
132
- if ( isset( $_GET['wpo_wcpdf_hide_extensions_ad'] ) ) {
133
- update_option( 'wpo_wcpdf_hide_extensions_ad', true );
134
- $hide_ad = true;
135
- } else {
136
- $hide_ad = get_option( 'wpo_wcpdf_hide_extensions_ad' );
137
- }
138
-
139
- if ( !$hide_ad && !( class_exists('WooCommerce_PDF_IPS_Pro') && class_exists('WooCommerce_PDF_IPS_Dropbox') && class_exists('WooCommerce_PDF_IPS_Templates') && class_exists('WooCommerce_Ext_PrintOrders') ) ) {
140
- include('wcpdf-extensions.php');
141
- }
142
-
143
- ?>
144
- <form method="post" action="options.php" id="wpo-wcpdf-settings">
145
- <?php
146
- do_action( 'wpo_wcpdf_before_settings', $active_tab );
147
- settings_fields( 'wpo_wcpdf_'.$active_tab.'_settings' );
148
- do_settings_sections( 'wpo_wcpdf_'.$active_tab.'_settings' );
149
- do_action( 'wpo_wcpdf_after_settings', $active_tab );
150
-
151
- submit_button();
152
- ?>
153
-
154
- </form>
155
- <?php
156
-
157
- if ( $active_tab=='debug' ) {
158
- $this->status_page();
159
- }
160
-
161
- do_action( 'wpo_wcpdf_after_settings_page', $active_tab ); ?>
162
-
163
- </div>
164
-
165
- <?php
166
- }
167
-
168
- public function status_page() {
169
- ?>
170
- <?php include('dompdf-status.php'); ?>
171
- <?php
172
- }
173
-
174
- /**
175
- * User settings.
176
- *
177
- */
178
-
179
- public function init_settings() {
180
- global $woocommerce, $wpo_wcpdf;
181
-
182
- /**************************************/
183
- /*********** GENERAL SETTINGS *********/
184
- /**************************************/
185
-
186
- $option = 'wpo_wcpdf_general_settings';
187
-
188
- // Create option in wp_options.
189
- if ( false === get_option( $option ) ) {
190
- $this->default_settings( $option );
191
- }
192
-
193
- // Section.
194
- add_settings_section(
195
- 'general_settings',
196
- __( 'General settings', 'wpo_wcpdf' ),
197
- array( &$this, 'section_options_callback' ),
198
- $option
199
- );
200
-
201
- add_settings_field(
202
- 'download_display',
203
- __( 'How do you want to view the PDF?', 'wpo_wcpdf' ),
204
- array( &$this, 'select_element_callback' ),
205
- $option,
206
- 'general_settings',
207
- array(
208
- 'menu' => $option,
209
- 'id' => 'download_display',
210
- 'options' => array(
211
- 'download' => __( 'Download the PDF' , 'wpo_wcpdf' ),
212
- 'display' => __( 'Open the PDF in a new browser tab/window' , 'wpo_wcpdf' ),
213
- ),
214
- )
215
- );
216
-
217
- $tmp_path = $wpo_wcpdf->export->tmp_path( 'attachments' );
218
- $tmp_path_check = !is_writable( $tmp_path );
219
-
220
- $wc_emails = array(
221
- 'new_order' => __( 'Admin New Order email' , 'wpo_wcpdf' ),
222
- 'processing' => __( 'Customer Processing Order email' , 'wpo_wcpdf' ),
223
- 'completed' => __( 'Customer Completed Order email' , 'wpo_wcpdf' ),
224
- 'customer_invoice' => __( 'Customer Invoice email' , 'wpo_wcpdf' ),
225
- );
226
-
227
- // load custom emails
228
- $extra_emails = $this->get_wc_emails();
229
- $wc_emails = array_merge( $wc_emails, $extra_emails );
230
-
231
- add_settings_field(
232
- 'email_pdf',
233
- __( 'Attach invoice to:', 'wpo_wcpdf' ),
234
- array( &$this, 'multiple_checkbox_element_callback' ),
235
- $option,
236
- 'general_settings',
237
- array(
238
- 'menu' => $option,
239
- 'id' => 'email_pdf',
240
- 'options' => apply_filters( 'wpo_wcpdf_wc_emails', $wc_emails ),
241
- 'description' => $tmp_path_check ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'wpo_wcpdf' ), $tmp_path ).'</span>':'',
242
- )
243
- );
244
-
245
- add_settings_field(
246
- 'disable_free',
247
- __( 'Disable for free products', 'wpo_wcpdf' ),
248
- array( &$this, 'checkbox_element_callback' ),
249
- $option,
250
- 'general_settings',
251
- array(
252
- 'menu' => $option,
253
- 'id' => 'disable_free',
254
- 'description' => __( "Disable automatic creation/attachment of invoices when only free products are ordered", 'wpo_wcpdf' ),
255
- )
256
- );
257
-
258
- // Section.
259
- add_settings_section(
260
- 'interface',
261
- __( 'Interface', 'wpo_wcpdf' ),
262
- array( &$this, 'section_options_callback' ),
263
- $option
264
- );
265
-
266
- // $documents = array(
267
- // 'invoice' => __( 'Invoice', 'wpo_wcpdf' ),
268
- // 'packing-slip' => __( 'Packing Slip', 'wpo_wcpdf' ),
269
- // );
270
-
271
- // $contexts = array(
272
- // 'orders-list' => __( 'Orders list', 'wpo_wcpdf' ),
273
- // 'orders-bulk' => __( 'Bulk order actions', 'wpo_wcpdf' ),
274
- // 'order-single' => __( 'Single order page', 'wpo_wcpdf' ),
275
- // 'my-account' => __( 'My Account page', 'wpo_wcpdf' ),
276
- // );
277
-
278
- // add_settings_field(
279
- // 'buttons',
280
- // __( 'Show download buttons', 'wpo_wcpdf' ),
281
- // array( &$this, 'checkbox_table_callback' ),
282
- // $option,
283
- // 'interface',
284
- // array(
285
- // 'menu' => $option,
286
- // 'id' => 'buttons',
287
- // 'rows' => $contexts,
288
- // 'columns' => apply_filters( 'wpo_wcpdf_documents_buttons', $documents ),
289
- // )
290
- // );
291
-
292
- // get list of WooCommerce statuses
293
- if ( version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
294
- $statuses = (array) get_terms( 'shop_order_status', array( 'hide_empty' => 0, 'orderby' => 'id' ) );
295
- foreach ( $statuses as $status ) {
296
- $order_statuses[esc_attr( $status->slug )] = esc_html__( $status->name, 'woocommerce' );
297
- }
298
- } else {
299
- $statuses = wc_get_order_statuses();
300
- foreach ( $statuses as $status_slug => $status ) {
301
- $status_slug = 'wc-' === substr( $status_slug, 0, 3 ) ? substr( $status_slug, 3 ) : $status_slug;
302
- $order_statuses[$status_slug] = $status;
303
- }
304
-
305
- }
306
-
307
- add_settings_field(
308
- 'my_account_buttons',
309
- __( 'Allow My Account invoice download', 'wpo_wcpdf' ),
310
- array( &$this, 'select_element_callback' ),
311
- $option,
312
- 'interface',
313
- array(
314
- 'menu' => $option,
315
- 'id' => 'my_account_buttons',
316
- 'options' => array(
317
- 'available' => __( 'Only when an invoice is already created/emailed' , 'wpo_wcpdf' ),
318
- 'custom' => __( 'Only for specific order statuses (define below)' , 'wpo_wcpdf' ),
319
- 'always' => __( 'Always' , 'wpo_wcpdf' ),
320
- 'never' => __( 'Never' , 'wpo_wcpdf' ),
321
- ),
322
- 'custom' => array(
323
- 'type' => 'multiple_checkbox_element_callback',
324
- 'args' => array(
325
- 'menu' => $option,
326
- 'id' => 'my_account_restrict',
327
- 'options' => $order_statuses,
328
- ),
329
- ),
330
- )
331
- );
332
-
333
- add_settings_field(
334
- 'invoice_number_column',
335
- __( 'Enable invoice number column in the orders list', 'wpo_wcpdf' ),
336
- array( &$this, 'checkbox_element_callback' ),
337
- $option,
338
- 'interface',
339
- array(
340
- 'menu' => $option,
341
- 'id' => 'invoice_number_column',
342
- )
343
- );
344
-
345
- // Register settings.
346
- register_setting( $option, $option, array( &$this, 'validate_options' ) );
347
-
348
- $option_values = get_option($option);
349
- // convert old 'statusless' setting to new status array
350
- if ( isset( $option_values['email_pdf'] ) && !is_array( $option_values['email_pdf'] ) ) {
351
- $default_status = apply_filters( 'wpo_wcpdf_attach_to_status', 'completed' );
352
- $option_values['email_pdf'] = array (
353
- $default_status => 1,
354
- 'customer_invoice' => 1,
355
- );
356
- update_option( $option, $option_values );
357
- }
358
-
359
- /**************************************/
360
- /********** TEMPLATE SETTINGS *********/
361
- /**************************************/
362
-
363
- $option = 'wpo_wcpdf_template_settings';
364
-
365
- // Create option in wp_options.
366
- if ( false === get_option( $option ) ) {
367
- $this->default_settings( $option );
368
- }
369
-
370
- // Section.
371
- add_settings_section(
372
- 'template_settings',
373
- __( 'PDF Template settings', 'wpo_wcpdf' ),
374
- array( &$this, 'section_options_callback' ),
375
- $option
376
- );
377
-
378
-
379
- $theme_path = get_stylesheet_directory() . '/' . $wpo_wcpdf->export->template_base_path;
380
- $theme_template_path = substr($theme_path, strpos($theme_path, 'wp-content')) . 'yourtemplate';
381
- $plugin_template_path = 'wp-content/plugins/woocommerce-pdf-invoices-packing-slips/templates/pdf/Simple';
382
-
383
- add_settings_field(
384
- 'template_path',
385
- __( 'Choose a template', 'wpo_wcpdf' ),
386
- array( &$this, 'template_select_element_callback' ),
387
- $option,
388
- 'template_settings',
389
- array(
390
- 'menu' => $option,
391
- 'id' => 'template_path',
392
- 'options' => $this->find_templates(),
393
- 'description' => sprintf( __( 'Want to use your own template? Copy all the files from <code>%s</code> to your (child) theme in <code>%s</code> to customize them' , 'wpo_wcpdf' ), $plugin_template_path, $theme_template_path),
394
- )
395
- );
396
-
397
- add_settings_field(
398
- 'paper_size',
399
- __( 'Paper size', 'wpo_wcpdf' ),
400
- array( &$this, 'select_element_callback' ),
401
- $option,
402
- 'template_settings',
403
- array(
404
- 'menu' => $option,
405
- 'id' => 'paper_size',
406
- 'options' => apply_filters( 'wpo_wcpdf_template_settings_paper_size', array(
407
- 'a4' => __( 'A4' , 'wpo_wcpdf' ),
408
- 'letter' => __( 'Letter' , 'wpo_wcpdf' ),
409
- ) ),
410
- )
411
- );
412
-
413
- add_settings_field(
414
- 'header_logo',
415
- __( 'Shop header/logo', 'wpo_wcpdf' ),
416
- array( &$this, 'media_upload_callback' ),
417
- $option,
418
- 'template_settings',
419
- array(
420
- 'menu' => $option,
421
- 'id' => 'header_logo',
422
- 'uploader_title' => __( 'Select or upload your invoice header/logo', 'wpo_wcpdf' ),
423
- 'uploader_button_text' => __( 'Set image', 'wpo_wcpdf' ),
424
- 'remove_button_text' => __( 'Remove image', 'wpo_wcpdf' ),
425
- //'description' => __( '...', 'wpo_wcpdf' ),
426
- )
427
- );
428
-
429
- add_settings_field(
430
- 'shop_name',
431
- __( 'Shop Name', 'wpo_wcpdf' ),
432
- array( &$this, 'text_element_callback' ),
433
- $option,
434
- 'template_settings',
435
- array(
436
- 'menu' => $option,
437
- 'id' => 'shop_name',
438
- 'size' => '72',
439
- 'translatable' => true,
440
- )
441
- );
442
-
443
- add_settings_field(
444
- 'shop_address',
445
- __( 'Shop Address', 'wpo_wcpdf' ),
446
- array( &$this, 'textarea_element_callback' ),
447
- $option,
448
- 'template_settings',
449
- array(
450
- 'menu' => $option,
451
- 'id' => 'shop_address',
452
- 'width' => '72',
453
- 'height' => '8',
454
- 'translatable' => true,
455
- //'description' => __( '...', 'wpo_wcpdf' ),
456
- )
457
- );
458
-
459
- add_settings_field(
460
- 'footer',
461
- __( 'Footer: terms & conditions, policies, etc.', 'wpo_wcpdf' ),
462
- array( &$this, 'textarea_element_callback' ),
463
- $option,
464
- 'template_settings',
465
- array(
466
- 'menu' => $option,
467
- 'id' => 'footer',
468
- 'width' => '72',
469
- 'height' => '4',
470
- 'translatable' => true,
471
- //'description' => __( '...', 'wpo_wcpdf' ),
472
- )
473
- );
474
-
475
- // Section.
476
- add_settings_section(
477
- 'invoice',
478
- __( 'Invoice', 'wpo_wcpdf' ),
479
- array( &$this, 'section_options_callback' ),
480
- $option
481
- );
482
-
483
- add_settings_field(
484
- 'invoice_shipping_address',
485
- __( 'Display shipping address', 'wpo_wcpdf' ),
486
- array( &$this, 'checkbox_element_callback' ),
487
- $option,
488
- 'invoice',
489
- array(
490
- 'menu' => $option,
491
- 'id' => 'invoice_shipping_address',
492
- 'description' => __( 'Display shipping address on invoice (in addition to the default billing address) if different from billing address', 'wpo_wcpdf' ),
493
- )
494
- );
495
-
496
- add_settings_field(
497
- 'invoice_email',
498
- __( 'Display email address', 'wpo_wcpdf' ),
499
- array( &$this, 'checkbox_element_callback' ),
500
- $option,
501
- 'invoice',
502
- array(
503
- 'menu' => $option,
504
- 'id' => 'invoice_email',
505
- )
506
- );
507
-
508
- add_settings_field(
509
- 'invoice_phone',
510
- __( 'Display phone number', 'wpo_wcpdf' ),
511
- array( &$this, 'checkbox_element_callback' ),
512
- $option,
513
- 'invoice',
514
- array(
515
- 'menu' => $option,
516
- 'id' => 'invoice_phone',
517
- )
518
- );
519
-
520
- add_settings_field(
521
- 'display_date',
522
- __( 'Display invoice date', 'wpo_wcpdf' ),
523
- array( &$this, 'checkbox_element_callback' ),
524
- $option,
525
- 'invoice',
526
- array(
527
- 'menu' => $option,
528
- 'id' => 'display_date',
529
- 'value' => 'invoice_date',
530
- )
531
- );
532
-
533
- add_settings_field(
534
- 'display_number',
535
- __( 'Display built-in sequential invoice number', 'wpo_wcpdf' ),
536
- array( &$this, 'checkbox_element_callback' ),
537
- $option,
538
- 'invoice',
539
- array(
540
- 'menu' => $option,
541
- 'id' => 'display_number',
542
- 'value' => 'invoice_number',
543
- )
544
- );
545
-
546
- // invoice number is stored separately for direct retrieval
547
- register_setting( $option, 'wpo_wcpdf_next_invoice_number', array( &$this, 'validate_options' ) );
548
- add_settings_field(
549
- 'next_invoice_number',
550
- __( 'Next invoice number (without prefix/suffix etc.)', 'wpo_wcpdf' ),
551
- array( &$this, 'singular_text_element_callback' ),
552
- $option,
553
- 'invoice',
554
- array(
555
- 'menu' => 'wpo_wcpdf_next_invoice_number',
556
- 'id' => 'next_invoice_number',
557
- 'size' => '10',
558
- 'description' => __( 'This is the number that will be used on the next invoice that is created. By default, numbering starts from the WooCommerce Order Number of the first invoice that is created and increases for every new invoice. Note that if you override this and set it lower than the highest (PDF) invoice number, this could create double invoice numbers!', 'wpo_wcpdf' ),
559
- )
560
- );
561
-
562
- // first time invoice number
563
- $next_invoice_number = get_option('wpo_wcpdf_next_invoice_number');
564
- // determine highest invoice number if option not set
565
- if ( !isset( $next_invoice_number ) ) {
566
- // Based on code from WooCommerce Sequential Order Numbers
567
- global $wpdb;
568
- // get highest invoice_number in postmeta table
569
- $max_invoice_number = $wpdb->get_var( 'SELECT max(cast(meta_value as UNSIGNED)) from ' . $wpdb->postmeta . ' where meta_key="_wcpdf_invoice_number"' );
570
-
571
- if ( !empty($max_invoice_number) ) {
572
- $next_invoice_number = $max_invoice_number+1;
573
- } else {
574
- $next_invoice_number = '';
575
- }
576
-
577
- update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
578
- }
579
-
580
- add_settings_field(
581
- 'invoice_number_formatting',
582
- __( 'Invoice number format', 'wpo_wcpdf' ),
583
- array( &$this, 'invoice_number_formatting_callback' ),
584
- $option,
585
- 'invoice',
586
- array(
587
- 'menu' => $option,
588
- 'id' => 'invoice_number_formatting',
589
- 'fields' => array(
590
- 'prefix' => array(
591
- 'title' => __( 'Prefix' , 'wpo_wcpdf' ),
592
- 'size' => 20,
593
- 'description' => __( 'to use the invoice year and/or month, use [invoice_year] or [invoice_month] respectively' , 'wpo_wcpdf' ),
594
- ),
595
- 'suffix' => array(
596
- 'title' => __( 'Suffix' , 'wpo_wcpdf' ),
597
- 'size' => 20,
598
- 'description' => '',
599
- ),
600
- 'padding' => array(
601
- 'title' => __( 'Padding' , 'wpo_wcpdf' ),
602
- 'size' => 2,
603
- 'description' => __( 'enter the number of digits here - enter "6" to display 42 as 000042' , 'wpo_wcpdf' ),
604
- ),
605
- ),
606
- 'description' => __( 'note: if you have already created a custom invoice number format with a filter, the above settings will be ignored' , 'wpo_wcpdf' ),
607
- )
608
- );
609
-
610
- add_settings_field(
611
- 'yearly_reset_invoice_number',
612
- __( 'Reset invoice number yearly', 'wpo_wcpdf' ),
613
- array( &$this, 'checkbox_element_callback' ),
614
- $option,
615
- 'invoice',
616
- array(
617
- 'menu' => $option,
618
- 'id' => 'yearly_reset_invoice_number',
619
- )
620
- );
621
-
622
- add_settings_field(
623
- 'currency_font',
624
- __( 'Extended currency symbol support', 'wpo_wcpdf' ),
625
- array( &$this, 'checkbox_element_callback' ),
626
- $option,
627
- 'invoice',
628
- array(
629
- 'menu' => $option,
630
- 'id' => 'currency_font',
631
- 'description' => __( 'Enable this if your currency symbol is not displaying properly' , 'wpo_wcpdf' ),
632
- )
633
- );
634
-
635
- // Section.
636
- add_settings_section(
637
- 'packing_slip',
638
- __( 'Packing Slip', 'wpo_wcpdf' ),
639
- array( &$this, 'section_options_callback' ),
640
- $option
641
- );
642
-
643
- add_settings_field(
644
- 'packing_slip_billing_address',
645
- __( 'Display billing address', 'wpo_wcpdf' ),
646
- array( &$this, 'checkbox_element_callback' ),
647
- $option,
648
- 'packing_slip',
649
- array(
650
- 'menu' => $option,
651
- 'id' => 'packing_slip_billing_address',
652
- 'description' => __( 'Display billing address on packing slip (in addition to the default shipping address) if different from shipping address', 'wpo_wcpdf' ),
653
- )
654
- );
655
-
656
- add_settings_field(
657
- 'packing_slip_email',
658
- __( 'Display email address', 'wpo_wcpdf' ),
659
- array( &$this, 'checkbox_element_callback' ),
660
- $option,
661
- 'packing_slip',
662
- array(
663
- 'menu' => $option,
664
- 'id' => 'packing_slip_email',
665
- )
666
- );
667
-
668
- add_settings_field(
669
- 'packing_slip_phone',
670
- __( 'Display phone number', 'wpo_wcpdf' ),
671
- array( &$this, 'checkbox_element_callback' ),
672
- $option,
673
- 'packing_slip',
674
- array(
675
- 'menu' => $option,
676
- 'id' => 'packing_slip_phone',
677
- )
678
- );
679
-
680
- // Section.
681
- add_settings_section(
682
- 'extra_template_fields',
683
- __( 'Extra template fields', 'wpo_wcpdf' ),
684
- array( &$this, 'custom_fields_section' ),
685
- $option
686
- );
687
-
688
- add_settings_field(
689
- 'extra_1',
690
- __( 'Extra field 1', 'wpo_wcpdf' ),
691
- array( &$this, 'textarea_element_callback' ),
692
- $option,
693
- 'extra_template_fields',
694
- array(
695
- 'menu' => $option,
696
- 'id' => 'extra_1',
697
- 'width' => '72',
698
- 'height' => '8',
699
- 'description' => __( 'This is footer column 1 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
700
- 'translatable' => true,
701
- )
702
- );
703
-
704
- add_settings_field(
705
- 'extra_2',
706
- __( 'Extra field 2', 'wpo_wcpdf' ),
707
- array( &$this, 'textarea_element_callback' ),
708
- $option,
709
- 'extra_template_fields',
710
- array(
711
- 'menu' => $option,
712
- 'id' => 'extra_2',
713
- 'width' => '72',
714
- 'height' => '8',
715
- 'description' => __( 'This is footer column 2 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
716
- 'translatable' => true,
717
- )
718
- );
719
-
720
- add_settings_field(
721
- 'extra_3',
722
- __( 'Extra field 3', 'wpo_wcpdf' ),
723
- array( &$this, 'textarea_element_callback' ),
724
- $option,
725
- 'extra_template_fields',
726
- array(
727
- 'menu' => $option,
728
- 'id' => 'extra_3',
729
- 'width' => '72',
730
- 'height' => '8',
731
- 'description' => __( 'This is footer column 3 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
732
- 'translatable' => true,
733
- )
734
- );
735
-
736
- // Register settings.
737
- register_setting( $option, $option, array( &$this, 'validate_options' ) );
738
-
739
- /**************************************/
740
- /******** DEBUG/STATUS SETTINGS *******/
741
- /**************************************/
742
-
743
- $option = 'wpo_wcpdf_debug_settings';
744
-
745
- // Create option in wp_options.
746
- if ( false === get_option( $option ) ) {
747
- $this->default_settings( $option );
748
- }
749
-
750
- // Section.
751
- add_settings_section(
752
- 'debug_settings',
753
- __( 'Debug settings', 'wpo_wcpdf' ),
754
- array( &$this, 'debug_section' ),
755
- $option
756
- );
757
-
758
- add_settings_field(
759
- 'enable_debug',
760
- __( 'Enable debug output', 'wpo_wcpdf' ),
761
- array( &$this, 'checkbox_element_callback' ),
762
- $option,
763
- 'debug_settings',
764
- array(
765
- 'menu' => $option,
766
- 'id' => 'enable_debug',
767
- 'description' => __( "Enable this option to output plugin errors if you're getting a blank page or other PDF generation issues", 'wpo_wcpdf' ),
768
- )
769
- );
770
-
771
- add_settings_field(
772
- 'html_output',
773
- __( 'Output to HTML', 'wpo_wcpdf' ),
774
- array( &$this, 'checkbox_element_callback' ),
775
- $option,
776
- 'debug_settings',
777
- array(
778
- 'menu' => $option,
779
- 'id' => 'html_output',
780
- 'description' => __( 'Send the template output as HTML to the browser instead of creating a PDF.', 'wpo_wcpdf' ),
781
- )
782
- );
783
-
784
- add_settings_field(
785
- 'old_tmp',
786
- __( 'Use old tmp folder', 'wpo_wcpdf' ),
787
- array( &$this, 'checkbox_element_callback' ),
788
- $option,
789
- 'debug_settings',
790
- array(
791
- 'menu' => $option,
792
- 'id' => 'old_tmp',
793
- 'description' => __( 'Before version 1.5 of PDF Invoices, temporary files were stored in the plugin folder. This setting is only intended for backwards compatibility, not recommended on new installs!', 'wpo_wcpdf' ),
794
- )
795
- );
796
-
797
- // Register settings.
798
- register_setting( $option, $option, array( &$this, 'validate_options' ) );
799
-
800
- }
801
-
802
- /**
803
- * get all emails registered in WooCommerce
804
- * @param boolean $remove_defaults switch to remove default woocommerce emails
805
- * @return array $emails list of all email ids/slugs and names
806
- */
807
- public function get_wc_emails ( $remove_defaults = true ) {
808
- // get emails from WooCommerce
809
- global $woocommerce;
810
- $mailer = $woocommerce->mailer();
811
- $wc_emails = $mailer->get_emails();
812
-
813
- $default_emails = array(
814
- 'new_order',
815
- 'customer_processing_order',
816
- 'customer_completed_order',
817
- 'customer_invoice',
818
- 'customer_note',
819
- 'customer_reset_password',
820
- 'customer_new_account'
821
- );
822
-
823
- $emails = array();
824
- foreach ($wc_emails as $name => $template) {
825
- if ( !( $remove_defaults && in_array( $template->id, $default_emails ) ) ) {
826
- $emails[$template->id] = $template->title;
827
- }
828
- }
829
-
830
- return $emails;
831
- }
832
-
833
- /**
834
- * WooCommerce Order Status & Actions Manager emails compatibility
835
- */
836
- public function wc_order_status_actions_emails ( $emails ) {
837
- // check if WC_Custom_Status class is loaded!
838
- if (class_exists('WC_Custom_Status')) {
839
- // get list of custom statuses from WooCommerce Custom Order Status & Actions
840
- // status slug => status name
841
- $custom_statuses = WC_Custom_Status::get_status_list_names();
842
- // append _email to slug (=email_id) and add to emails list
843
- foreach ($custom_statuses as $status_slug => $status_name) {
844
- $emails[$status_slug.'_email'] = $status_name;
845
- }
846
- }
847
- return $emails;
848
- }
849
-
850
- /**
851
- * Set default settings.
852
- */
853
- public function default_settings( $option ) {
854
- global $wpo_wcpdf;
855
-
856
- switch ( $option ) {
857
- case 'wpo_wcpdf_general_settings':
858
- $default = array(
859
- 'download_display' => 'download',
860
- );
861
- break;
862
- case 'wpo_wcpdf_template_settings':
863
- $default = array(
864
- 'paper_size' => 'a4',
865
- 'template_path' => $wpo_wcpdf->export->template_default_base_path . 'Simple',
866
- // 'invoice_shipping_address' => '1',
867
- );
868
- break;
869
- default:
870
- $default = array();
871
- break;
872
- }
873
-
874
- if ( false === get_option( $option ) ) {
875
- add_option( $option, $default );
876
- } else {
877
- update_option( $option, $default );
878
-
879
- }
880
- }
881
-
882
- // Text element callback.
883
- public function text_element_callback( $args ) {
884
- $menu = $args['menu'];
885
- $id = $args['id'];
886
- $size = isset( $args['size'] ) ? $args['size'] : '25';
887
- $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
888
-
889
- $options = get_option( $menu );
890
-
891
- if ( isset( $options[$id] ) ) {
892
- $current = $options[$id];
893
- } else {
894
- $current = isset( $args['default'] ) ? $args['default'] : '';
895
- }
896
-
897
- $html = sprintf( '<input type="text" id="%1$s" name="%2$s[%1$s]" value="%3$s" size="%4$s" class="%5$s"/>', $id, $menu, $current, $size, $class );
898
-
899
- // Displays option description.
900
- if ( isset( $args['description'] ) ) {
901
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
902
- }
903
-
904
- echo $html;
905
- }
906
-
907
- // Single text option (not part of any settings array)
908
- public function singular_text_element_callback( $args ) {
909
- $menu = $args['menu'];
910
- $id = $args['id'];
911
- $size = isset( $args['size'] ) ? $args['size'] : '25';
912
- $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
913
-
914
- $option = get_option( $menu );
915
-
916
- if ( isset( $option ) ) {
917
- $current = $option;
918
- } else {
919
- $current = isset( $args['default'] ) ? $args['default'] : '';
920
- }
921
-
922
- $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $menu, $current, $size, $class );
923
-
924
- // Displays option description.
925
- if ( isset( $args['description'] ) ) {
926
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
927
- }
928
-
929
- echo $html;
930
- }
931
-
932
- // Text element callback.
933
- public function textarea_element_callback( $args ) {
934
- $menu = $args['menu'];
935
- $id = $args['id'];
936
- $width = $args['width'];
937
- $height = $args['height'];
938
- $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
939
-
940
- $options = get_option( $menu );
941
-
942
- if ( isset( $options[$id] ) ) {
943
- $current = $options[$id];
944
- } else {
945
- $current = isset( $args['default'] ) ? $args['default'] : '';
946
- }
947
-
948
- $html = sprintf( '<textarea id="%1$s" name="%2$s[%1$s]" cols="%4$s" rows="%5$s" class="%6$s"/>%3$s</textarea>', $id, $menu, $current, $width, $height, $class );
949
-
950
- // Displays option description.
951
- if ( isset( $args['description'] ) ) {
952
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
953
- }
954
-
955
- echo $html;
956
- }
957
-
958
-
959
- /**
960
- * Checkbox field callback.
961
- *
962
- * @param array $args Field arguments.
963
- *
964
- * @return string Checkbox field.
965
- */
966
- public function checkbox_element_callback( $args ) {
967
- $menu = $args['menu'];
968
- $id = $args['id'];
969
- $value = isset( $args['value'] ) ? $args['value'] : 1;
970
-
971
- $options = get_option( $menu );
972
-
973
- if ( isset( $options[$id] ) ) {
974
- $current = $options[$id];
975
- } else {
976
- $current = isset( $args['default'] ) ? $args['default'] : '';
977
- }
978
-
979
- $html = sprintf( '<input type="checkbox" id="%1$s" name="%2$s[%1$s]" value="%3$s"%4$s />', $id, $menu, $value, checked( $value, $current, false ) );
980
-
981
- // Displays option description.
982
- if ( isset( $args['description'] ) ) {
983
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
984
- }
985
-
986
- echo $html;
987
- }
988
-
989
- /**
990
- * Multiple Checkbox field callback.
991
- *
992
- * @param array $args Field arguments.
993
- *
994
- * @return string Checkbox field.
995
- */
996
- public function multiple_checkbox_element_callback( $args ) {
997
- $menu = $args['menu'];
998
- $id = $args['id'];
999
-
1000
- $options = get_option( $menu );
1001
-
1002
-
1003
- foreach ( $args['options'] as $key => $label ) {
1004
- $current = ( isset( $options[$id][$key] ) ) ? $options[$id][$key] : '';
1005
- printf( '<input type="checkbox" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="1"%4$s /> %5$s<br/>', $menu, $id, $key, checked( 1, $current, false ), $label );
1006
- }
1007
-
1008
- // Displays option description.
1009
- if ( isset( $args['description'] ) ) {
1010
- printf( '<p class="description">%s</p>', $args['description'] );
1011
- }
1012
- }
1013
-
1014
- /**
1015
- * Checkbox fields table callback.
1016
- *
1017
- * @param array $args Field arguments.
1018
- *
1019
- * @return string Checkbox field.
1020
- */
1021
- public function checkbox_table_callback( $args ) {
1022
- $menu = $args['menu'];
1023
- $id = $args['id'];
1024
-
1025
- $options = get_option( $menu );
1026
-
1027
- $rows = $args['rows'];
1028
- $columns = $args['columns'];
1029
-
1030
- ?>
1031
- <table style="">
1032
- <tr>
1033
- <td style="padding:0 10px 5px 0;">&nbsp;</td>
1034
- <?php foreach ( $columns as $column => $title ) { ?>
1035
- <td style="padding:0 10px 5px 0;"><?php echo $title; ?></td>
1036
- <?php } ?>
1037
- </tr>
1038
- <tr>
1039
- <td style="padding: 0;">
1040
- <?php foreach ($rows as $row) {
1041
- echo $row.'<br/>';
1042
- } ?>
1043
- </td>
1044
- <?php foreach ( $columns as $column => $title ) { ?>
1045
- <td style="text-align:center; padding: 0;">
1046
- <?php foreach ( $rows as $row => $title ) {
1047
- $current = ( isset( $options[$id.'_'.$column][$row] ) ) ? $options[$id.'_'.$column][$row] : '';
1048
- $name = sprintf('%1$s[%2$s_%3$s][%4$s]', $menu, $id, $column, $row);
1049
- printf( '<input type="checkbox" id="%1$s" name="%1$s" value="1"%2$s /><br/>', $name, checked( 1, $current, false ) );
1050
- } ?>
1051
- </td>
1052
- <?php } ?>
1053
- </tr>
1054
- </table>
1055
-
1056
- <?php
1057
- // Displays option description.
1058
- if ( isset( $args['description'] ) ) {
1059
- printf( '<p class="description">%s</p>', $args['description'] );
1060
- }
1061
- }
1062
-
1063
- /**
1064
- * Select element callback.
1065
- *
1066
- * @param array $args Field arguments.
1067
- *
1068
- * @return string Select field.
1069
- */
1070
- public function select_element_callback( $args ) {
1071
- $menu = $args['menu'];
1072
- $id = $args['id'];
1073
-
1074
- $options = get_option( $menu );
1075
-
1076
- if ( isset( $options[$id] ) ) {
1077
- $current = $options[$id];
1078
- } else {
1079
- $current = isset( $args['default'] ) ? $args['default'] : '';
1080
- }
1081
-
1082
- printf( '<select id="%1$s" name="%2$s[%1$s]">', $id, $menu );
1083
-
1084
- foreach ( $args['options'] as $key => $label ) {
1085
- printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
1086
- }
1087
-
1088
- echo '</select>';
1089
-
1090
-
1091
- if (isset($args['custom'])) {
1092
- $custom = $args['custom'];
1093
-
1094
- $custom_id = $id.'_custom';
1095
-
1096
- printf( '<br/><br/><div id="%s" style="display:none;">', $custom_id );
1097
-
1098
- switch ($custom['type']) {
1099
- case 'text_element_callback':
1100
- $this->text_element_callback( $custom['args'] );
1101
- break;
1102
- case 'multiple_text_element_callback':
1103
- $this->multiple_text_element_callback( $custom['args'] );
1104
- break;
1105
- case 'multiple_checkbox_element_callback':
1106
- $this->multiple_checkbox_element_callback( $custom['args'] );
1107
- break;
1108
- default:
1109
- break;
1110
- }
1111
-
1112
- echo '</div>';
1113
-
1114
- ?>
1115
- <script type="text/javascript">
1116
- jQuery(document).ready(function($) {
1117
- function check_<?php echo $id; ?>_custom() {
1118
- var custom = $('#<?php echo $id; ?>').val();
1119
- if (custom == 'custom') {
1120
- $( '#<?php echo $custom_id; ?>').show();
1121
- } else {
1122
- $( '#<?php echo $custom_id; ?>').hide();
1123
- }
1124
- }
1125
-
1126
- check_<?php echo $id; ?>_custom();
1127
-
1128
- $( '#<?php echo $id; ?>' ).change(function() {
1129
- check_<?php echo $id; ?>_custom();
1130
- });
1131
-
1132
- });
1133
- </script>
1134
- <?php
1135
- }
1136
-
1137
- // Displays option description.
1138
- if ( isset( $args['description'] ) ) {
1139
- printf( '<p class="description">%s</p>', $args['description'] );
1140
- }
1141
-
1142
- }
1143
-
1144
- /**
1145
- * Displays a radio settings field
1146
- *
1147
- * @param array $args settings field args
1148
- */
1149
- public function radio_element_callback( $args ) {
1150
- $menu = $args['menu'];
1151
- $id = $args['id'];
1152
-
1153
- $options = get_option( $menu );
1154
-
1155
- if ( isset( $options[$id] ) ) {
1156
- $current = $options[$id];
1157
- } else {
1158
- $current = isset( $args['default'] ) ? $args['default'] : '';
1159
- }
1160
-
1161
- $html = '';
1162
- foreach ( $args['options'] as $key => $label ) {
1163
- $html .= sprintf( '<input type="radio" class="radio" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s"%4$s />', $menu, $id, $key, checked( $current, $key, false ) );
1164
- $html .= sprintf( '<label for="%1$s[%2$s][%3$s]"> %4$s</label><br>', $menu, $id, $key, $label);
1165
- }
1166
-
1167
- // Displays option description.
1168
- if ( isset( $args['description'] ) ) {
1169
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1170
- }
1171
-
1172
- echo $html;
1173
- }
1174
-
1175
- /**
1176
- * Media upload callback.
1177
- *
1178
- * @param array $args Field arguments.
1179
- *
1180
- * @return string Media upload button & preview.
1181
- */
1182
- public function media_upload_callback( $args ) {
1183
- $menu = $args['menu'];
1184
- $id = $args['id'];
1185
- $options = get_option( $menu );
1186
-
1187
- if ( isset( $options[$id] ) ) {
1188
- $current = $options[$id];
1189
- } else {
1190
- $current = isset( $args['default'] ) ? $args['default'] : '';
1191
- }
1192
-
1193
- $uploader_title = $args['uploader_title'];
1194
- $uploader_button_text = $args['uploader_button_text'];
1195
- $remove_button_text = $args['remove_button_text'];
1196
-
1197
- $html = '';
1198
- if( !empty($current) ) {
1199
- $attachment = wp_get_attachment_image_src( $current, 'full', false );
1200
-
1201
- $attachment_src = $attachment[0];
1202
- $attachment_width = $attachment[1];
1203
- $attachment_height = $attachment[2];
1204
-
1205
- $attachment_resolution = round($attachment_height/(3/2.54));
1206
-
1207
- $html .= sprintf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
1208
- $html .= '<div class="attachment-resolution"><p class="description">'.__('Image resolution').': '.$attachment_resolution.'dpi (default height = 3cm)</p></div>';
1209
- $html .= sprintf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
1210
- }
1211
-
1212
- $html .= sprintf( '<input id="%1$s" name="%2$s[%1$s]" type="hidden" value="%3$s" />', $id, $menu, $current );
1213
-
1214
- $html .= sprintf( '<span class="button wpo_upload_image_button %4$s" data-uploader_title="%1$s" data-uploader_button_text="%2$s" data-remove_button_text="%3$s" data-input_id="%4$s">%2$s</span>', $uploader_title, $uploader_button_text, $remove_button_text, $id );
1215
-
1216
- // Displays option description.
1217
- if ( isset( $args['description'] ) ) {
1218
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1219
- }
1220
-
1221
- echo $html;
1222
- }
1223
-
1224
- /**
1225
- * Invoice number formatting callback.
1226
- *
1227
- * @param array $args Field arguments.
1228
- *
1229
- * @return string Media upload button & preview.
1230
- */
1231
- public function invoice_number_formatting_callback( $args ) {
1232
- $menu = $args['menu'];
1233
- $fields = $args['fields'];
1234
- $options = get_option( $menu );
1235
-
1236
- echo '<table>';
1237
- foreach ($fields as $key => $field) {
1238
- $id = $args['id'] . '_' . $key;
1239
-
1240
- if ( isset( $options[$id] ) ) {
1241
- $current = $options[$id];
1242
- } else {
1243
- $current = '';
1244
- }
1245
-
1246
- $title = $field['title'];
1247
- $size = $field['size'];
1248
- $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
1249
-
1250
- echo '<tr>';
1251
- printf( '<td style="padding:0 1em 0 0; ">%1$s:</td><td style="padding:0;"><input type="text" id="%2$s" name="%3$s[%2$s]" value="%4$s" size="%5$s"/></td><td style="padding:0 0 0 1em;">%6$s</td>', $title, $id, $menu, $current, $size, $description );
1252
- echo '</tr>';
1253
- }
1254
- echo '</table>';
1255
-
1256
-
1257
- // Displays option description.
1258
- if ( isset( $args['description'] ) ) {
1259
- printf( '<p class="description">%s</p>', $args['description'] );
1260
- }
1261
-
1262
- // echo $html;
1263
- }
1264
-
1265
-
1266
- /**
1267
- * Template select element callback.
1268
- *
1269
- * @param array $args Field arguments.
1270
- *
1271
- * @return string Select field.
1272
- */
1273
- public function template_select_element_callback( $args ) {
1274
- $menu = $args['menu'];
1275
- $id = $args['id'];
1276
-
1277
- $options = get_option( $menu );
1278
-
1279
- if ( isset( $options[$id] ) ) {
1280
- $current = $options[$id];
1281
- } else {
1282
- $current = isset( $args['default'] ) ? $args['default'] : '';
1283
- }
1284
-
1285
- $html = sprintf( '<select id="%1$s" name="%2$s[%1$s]">', $id, $menu );
1286
-
1287
- // backwards compatible template path (1.4.4+ uses relative paths instead of absolute)
1288
- if (strpos($current, ABSPATH) !== false) {
1289
- // check if folder exists, then strip site base path.
1290
- if ( file_exists( $current ) ) {
1291
- $current = str_replace( ABSPATH, '', $current );
1292
- }
1293
- }
1294
-
1295
- foreach ( $args['options'] as $key => $label ) {
1296
- $html .= sprintf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
1297
- }
1298
-
1299
- $html .= '</select>';
1300
-
1301
- // Displays option description.
1302
- if ( isset( $args['description'] ) ) {
1303
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1304
- }
1305
-
1306
- echo $html;
1307
-
1308
- }
1309
-
1310
- /**
1311
- * Section null callback.
1312
- *
1313
- * @return void.
1314
- */
1315
- public function section_options_callback() {
1316
- }
1317
-
1318
- /**
1319
- * Debug section callback.
1320
- *
1321
- * @return void.
1322
- */
1323
- public function debug_section() {
1324
- _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'wpo_wcpdf' );
1325
- }
1326
-
1327
- /**
1328
- * Custom fields section callback.
1329
- *
1330
- * @return void.
1331
- */
1332
- public function custom_fields_section() {
1333
- _e( 'These are used for the (optional) footer columns in the <em>Modern (Premium)</em> template, but can also be used for other elements in your custom template' , 'wpo_wcpdf' );
1334
- }
1335
-
1336
- /**
1337
- * Validate options.
1338
- *
1339
- * @param array $input options to valid.
1340
- *
1341
- * @return array validated options.
1342
- */
1343
- public function validate_options( $input ) {
1344
- // Create our array for storing the validated options.
1345
- $output = array();
1346
-
1347
- if (empty($input) || !is_array($input)) {
1348
- return $input;
1349
- }
1350
-
1351
- // Loop through each of the incoming options.
1352
- foreach ( $input as $key => $value ) {
1353
-
1354
- // Check to see if the current option has a value. If so, process it.
1355
- if ( isset( $input[$key] ) ) {
1356
- if ( is_array( $input[$key] ) ) {
1357
- foreach ( $input[$key] as $sub_key => $sub_value ) {
1358
- $output[$key][$sub_key] = $input[$key][$sub_key];
1359
- }
1360
- } else {
1361
- $output[$key] = $input[$key];
1362
- }
1363
- }
1364
- }
1365
-
1366
- // Return the array processing any additional functions filtered by this action.
1367
- return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
1368
- }
1369
-
1370
- /**
1371
- * List templates in plugin folder, theme folder & child theme folder
1372
- * @return array template path => template name
1373
- */
1374
- public function find_templates() {
1375
- global $wpo_wcpdf;
1376
- $installed_templates = array();
1377
-
1378
- // get base paths
1379
- $template_paths = array (
1380
- // note the order: child-theme before theme, so that array_unique filters out parent doubles
1381
- 'default' => $wpo_wcpdf->export->template_default_base_path,
1382
- 'child-theme' => get_stylesheet_directory() . '/' . $wpo_wcpdf->export->template_base_path,
1383
- 'theme' => get_template_directory() . '/' . $wpo_wcpdf->export->template_base_path,
1384
- );
1385
-
1386
- $template_paths = apply_filters( 'wpo_wcpdf_template_paths', $template_paths );
1387
-
1388
- foreach ($template_paths as $template_source => $template_path) {
1389
- $dirs = (array) glob( $template_path . '*' , GLOB_ONLYDIR);
1390
-
1391
- foreach ($dirs as $dir) {
1392
- if ( file_exists($dir."/invoice.php") && file_exists($dir."/packing-slip.php"))
1393
- // we're stripping abspath to make the plugin settings more portable
1394
- $installed_templates[ str_replace( ABSPATH, '', $dir )] = basename($dir);
1395
- }
1396
- }
1397
-
1398
- // remove parent doubles
1399
- $installed_templates = array_unique($installed_templates);
1400
-
1401
- if (empty($installed_templates)) {
1402
- // fallback to Simple template for servers with glob() disabled
1403
- $simple_template_path = str_replace( ABSPATH, '', $template_paths['default'] . 'Simple' );
1404
- $installed_templates[$simple_template_path] = 'Simple';
1405
- }
1406
-
1407
- return apply_filters( 'wpo_wcpdf_templates', $installed_templates );
1408
- }
1409
-
1410
- } // end class WooCommerce_PDF_Invoices_Settings
1411
-
1412
  } // end class_exists
1
+ <?php
2
+
3
+ /**
4
+ * Settings class
5
+ */
6
+ if ( ! class_exists( 'WooCommerce_PDF_Invoices_Settings' ) ) {
7
+
8
+ class WooCommerce_PDF_Invoices_Settings {
9
+
10
+ public $options_page_hook;
11
+ public $general_settings;
12
+ public $template_settings;
13
+
14
+ public function __construct() {
15
+ add_action( 'admin_menu', array( &$this, 'menu' ) ); // Add menu.
16
+ add_action( 'admin_init', array( &$this, 'init_settings' ) ); // Registers settings
17
+ add_filter( 'option_page_capability_wpo_wcpdf_template_settings', array( &$this, 'settings_capabilities' ) );
18
+ add_filter( 'option_page_capability_wpo_wcpdf_general_settings', array( &$this, 'settings_capabilities' ) );
19
+ add_action( 'admin_enqueue_scripts', array( &$this, 'load_scripts_styles' ) ); // Load scripts
20
+
21
+ // Add links to WordPress plugins page
22
+ add_filter( 'plugin_action_links_'.WooCommerce_PDF_Invoices::$plugin_basename, array( &$this, 'wpo_wcpdf_add_settings_link' ) );
23
+ add_filter( 'plugin_row_meta', array( $this, 'add_support_links' ), 10, 2 );
24
+
25
+ $this->general_settings = get_option('wpo_wcpdf_general_settings');
26
+ $this->template_settings = get_option('wpo_wcpdf_template_settings');
27
+
28
+ // WooCommerce Order Status & Actions Manager emails compatibility
29
+ add_filter( 'wpo_wcpdf_wc_emails', array( $this, 'wc_order_status_actions_emails' ), 10, 1 );
30
+ }
31
+
32
+ public function menu() {
33
+ $parent_slug = 'woocommerce';
34
+
35
+ $this->options_page_hook = add_submenu_page(
36
+ $parent_slug,
37
+ __( 'PDF Invoices', 'wpo_wcpdf' ),
38
+ __( 'PDF Invoices', 'wpo_wcpdf' ),
39
+ 'manage_woocommerce',
40
+ 'wpo_wcpdf_options_page',
41
+ array( $this, 'settings_page' )
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Set capability for settings page
47
+ */
48
+ public function settings_capabilities() {
49
+ return 'manage_woocommerce';
50
+ }
51
+
52
+ /**
53
+ * Styles for settings page
54
+ */
55
+ public function load_scripts_styles ( $hook ) {
56
+ if( $hook != $this->options_page_hook )
57
+ return;
58
+
59
+ wp_enqueue_script(
60
+ 'wcpdf-upload-js',
61
+ plugins_url( 'js/media-upload.js' , dirname(__FILE__) ),
62
+ array( 'jquery' ),
63
+ WooCommerce_PDF_Invoices::$version
64
+ );
65
+
66
+ wp_enqueue_style(
67
+ 'wpo-wcpdf',
68
+ WooCommerce_PDF_Invoices::$plugin_url . 'css/style.css',
69
+ array(),
70
+ WooCommerce_PDF_Invoices::$version
71
+ );
72
+ wp_enqueue_media();
73
+ }
74
+
75
+ /**
76
+ * Add settings link to plugins page
77
+ */
78
+ public function wpo_wcpdf_add_settings_link( $links ) {
79
+ $settings_link = '<a href="admin.php?page=wpo_wcpdf_options_page">'. __( 'Settings', 'woocommerce' ) . '</a>';
80
+ array_push( $links, $settings_link );
81
+ return $links;
82
+ }
83
+
84
+ /**
85
+ * Add various support links to plugin page
86
+ * after meta (version, authors, site)
87
+ */
88
+ public function add_support_links( $links, $file ) {
89
+ if ( !current_user_can( 'install_plugins' ) ) {
90
+ return $links;
91
+ }
92
+
93
+ if ( $file == WooCommerce_PDF_Invoices::$plugin_basename ) {
94
+ // $links[] = '<a href="..." target="_blank" title="' . __( '...', 'wpo_wcpdf' ) . '">' . __( '...', 'wpo_wcpdf' ) . '</a>';
95
+ }
96
+ return $links;
97
+ }
98
+
99
+ public function settings_page() {
100
+ $settings_tabs = apply_filters( 'wpo_wcpdf_settings_tabs', array (
101
+ 'general' => __('General','wpo_wcpdf'),
102
+ 'template' => __('Template','wpo_wcpdf'),
103
+ )
104
+ );
105
+
106
+ // add status tab last in row
107
+ $settings_tabs['debug'] = __('Status','wpo_wcpdf');
108
+
109
+ $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'general';
110
+
111
+ ?>
112
+ <script type="text/javascript">
113
+ window.onload = function () {
114
+ document.getElementById("footer-thankyou").innerHTML = "If you like <strong>WooCommerce PDF Invoices & Packing Slips</strong> please leave us a <a href='https://wordpress.org/support/view/plugin-reviews/woocommerce-pdf-invoices-packing-slips?rate=5#postform'>★★★★★</a> rating. A huge thank you in advance!";
115
+ };
116
+ </script>
117
+ <div class="wrap">
118
+ <div class="icon32" id="icon-options-general"><br /></div>
119
+ <h2><?php _e( 'WooCommerce PDF Invoices', 'wpo_wcpdf' ); ?></h2>
120
+ <h2 class="nav-tab-wrapper">
121
+ <?php
122
+ foreach ($settings_tabs as $tab_slug => $tab_title ) {
123
+ printf('<a href="?page=wpo_wcpdf_options_page&tab=%1$s" class="nav-tab nav-tab-%1$s %2$s">%3$s</a>', $tab_slug, (($active_tab == $tab_slug) ? 'nav-tab-active' : ''), $tab_title);
124
+ }
125
+ ?>
126
+ </h2>
127
+
128
+ <?php
129
+ do_action( 'wpo_wcpdf_before_settings_page', $active_tab );
130
+
131
+ // save or check option to hide extensions ad
132
+ if ( isset( $_GET['wpo_wcpdf_hide_extensions_ad'] ) ) {
133
+ update_option( 'wpo_wcpdf_hide_extensions_ad', true );
134
+ $hide_ad = true;
135
+ } else {
136
+ $hide_ad = get_option( 'wpo_wcpdf_hide_extensions_ad' );
137
+ }
138
+
139
+ if ( !$hide_ad && !( class_exists('WooCommerce_PDF_IPS_Pro') && class_exists('WooCommerce_PDF_IPS_Dropbox') && class_exists('WooCommerce_PDF_IPS_Templates') && class_exists('WooCommerce_Ext_PrintOrders') ) ) {
140
+ include('wcpdf-extensions.php');
141
+ }
142
+
143
+ ?>
144
+ <form method="post" action="options.php" id="wpo-wcpdf-settings">
145
+ <?php
146
+ do_action( 'wpo_wcpdf_before_settings', $active_tab );
147
+ settings_fields( 'wpo_wcpdf_'.$active_tab.'_settings' );
148
+ do_settings_sections( 'wpo_wcpdf_'.$active_tab.'_settings' );
149
+ do_action( 'wpo_wcpdf_after_settings', $active_tab );
150
+
151
+ submit_button();
152
+ ?>
153
+
154
+ </form>
155
+ <?php
156
+
157
+ if ( $active_tab=='debug' ) {
158
+ $this->status_page();
159
+ }
160
+
161
+ do_action( 'wpo_wcpdf_after_settings_page', $active_tab ); ?>
162
+
163
+ </div>
164
+
165
+ <?php
166
+ }
167
+
168
+ public function status_page() {
169
+ ?>
170
+ <?php include('dompdf-status.php'); ?>
171
+ <?php
172
+ }
173
+
174
+ /**
175
+ * User settings.
176
+ *
177
+ */
178
+
179
+ public function init_settings() {
180
+ global $woocommerce, $wpo_wcpdf;
181
+
182
+ /**************************************/
183
+ /*********** GENERAL SETTINGS *********/
184
+ /**************************************/
185
+
186
+ $option = 'wpo_wcpdf_general_settings';
187
+
188
+ // Create option in wp_options.
189
+ if ( false === get_option( $option ) ) {
190
+ $this->default_settings( $option );
191
+ }
192
+
193
+ // Section.
194
+ add_settings_section(
195
+ 'general_settings',
196
+ __( 'General settings', 'wpo_wcpdf' ),
197
+ array( &$this, 'section_options_callback' ),
198
+ $option
199
+ );
200
+
201
+ add_settings_field(
202
+ 'download_display',
203
+ __( 'How do you want to view the PDF?', 'wpo_wcpdf' ),
204
+ array( &$this, 'select_element_callback' ),
205
+ $option,
206
+ 'general_settings',
207
+ array(
208
+ 'menu' => $option,
209
+ 'id' => 'download_display',
210
+ 'options' => array(
211
+ 'download' => __( 'Download the PDF' , 'wpo_wcpdf' ),
212
+ 'display' => __( 'Open the PDF in a new browser tab/window' , 'wpo_wcpdf' ),
213
+ ),
214
+ )
215
+ );
216
+
217
+ $tmp_path = $wpo_wcpdf->export->tmp_path( 'attachments' );
218
+ $tmp_path_check = !is_writable( $tmp_path );
219
+
220
+ $wc_emails = array(
221
+ 'new_order' => __( 'Admin New Order email' , 'wpo_wcpdf' ),
222
+ 'processing' => __( 'Customer Processing Order email' , 'wpo_wcpdf' ),
223
+ 'completed' => __( 'Customer Completed Order email' , 'wpo_wcpdf' ),
224
+ 'customer_invoice' => __( 'Customer Invoice email' , 'wpo_wcpdf' ),
225
+ );
226
+
227
+ // load custom emails
228
+ $extra_emails = $this->get_wc_emails();
229
+ $wc_emails = array_merge( $wc_emails, $extra_emails );
230
+
231
+ add_settings_field(
232
+ 'email_pdf',
233
+ __( 'Attach invoice to:', 'wpo_wcpdf' ),
234
+ array( &$this, 'multiple_checkbox_element_callback' ),
235
+ $option,
236
+ 'general_settings',
237
+ array(
238
+ 'menu' => $option,
239
+ 'id' => 'email_pdf',
240
+ 'options' => apply_filters( 'wpo_wcpdf_wc_emails', $wc_emails ),
241
+ 'description' => $tmp_path_check ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'wpo_wcpdf' ), $tmp_path ).'</span>':'',
242
+ )
243
+ );
244
+
245
+ add_settings_field(
246
+ 'disable_free',
247
+ __( 'Disable for free products', 'wpo_wcpdf' ),
248
+ array( &$this, 'checkbox_element_callback' ),
249
+ $option,
250
+ 'general_settings',
251
+ array(
252
+ 'menu' => $option,
253
+ 'id' => 'disable_free',
254
+ 'description' => __( "Disable automatic creation/attachment of invoices when only free products are ordered", 'wpo_wcpdf' ),
255
+ )
256
+ );
257
+
258
+ // Section.
259
+ add_settings_section(
260
+ 'interface',
261
+ __( 'Interface', 'wpo_wcpdf' ),
262
+ array( &$this, 'section_options_callback' ),
263
+ $option
264
+ );
265
+
266
+ // $documents = array(
267
+ // 'invoice' => __( 'Invoice', 'wpo_wcpdf' ),
268
+ // 'packing-slip' => __( 'Packing Slip', 'wpo_wcpdf' ),
269
+ // );
270
+
271
+ // $contexts = array(
272
+ // 'orders-list' => __( 'Orders list', 'wpo_wcpdf' ),
273
+ // 'orders-bulk' => __( 'Bulk order actions', 'wpo_wcpdf' ),
274
+ // 'order-single' => __( 'Single order page', 'wpo_wcpdf' ),
275
+ // 'my-account' => __( 'My Account page', 'wpo_wcpdf' ),
276
+ // );
277
+
278
+ // add_settings_field(
279
+ // 'buttons',
280
+ // __( 'Show download buttons', 'wpo_wcpdf' ),
281
+ // array( &$this, 'checkbox_table_callback' ),
282
+ // $option,
283
+ // 'interface',
284
+ // array(
285
+ // 'menu' => $option,
286
+ // 'id' => 'buttons',
287
+ // 'rows' => $contexts,
288
+ // 'columns' => apply_filters( 'wpo_wcpdf_documents_buttons', $documents ),
289
+ // )
290
+ // );
291
+
292
+ // get list of WooCommerce statuses
293
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
294
+ $statuses = (array) get_terms( 'shop_order_status', array( 'hide_empty' => 0, 'orderby' => 'id' ) );
295
+ foreach ( $statuses as $status ) {
296
+ $order_statuses[esc_attr( $status->slug )] = esc_html__( $status->name, 'woocommerce' );
297
+ }
298
+ } else {
299
+ $statuses = wc_get_order_statuses();
300
+ foreach ( $statuses as $status_slug => $status ) {
301
+ $status_slug = 'wc-' === substr( $status_slug, 0, 3 ) ? substr( $status_slug, 3 ) : $status_slug;
302
+ $order_statuses[$status_slug] = $status;
303
+ }
304
+
305
+ }
306
+
307
+ add_settings_field(
308
+ 'my_account_buttons',
309
+ __( 'Allow My Account invoice download', 'wpo_wcpdf' ),
310
+ array( &$this, 'select_element_callback' ),
311
+ $option,
312
+ 'interface',
313
+ array(
314
+ 'menu' => $option,
315
+ 'id' => 'my_account_buttons',
316
+ 'options' => array(
317
+ 'available' => __( 'Only when an invoice is already created/emailed' , 'wpo_wcpdf' ),
318
+ 'custom' => __( 'Only for specific order statuses (define below)' , 'wpo_wcpdf' ),
319
+ 'always' => __( 'Always' , 'wpo_wcpdf' ),
320
+ 'never' => __( 'Never' , 'wpo_wcpdf' ),
321
+ ),
322
+ 'custom' => array(
323
+ 'type' => 'multiple_checkbox_element_callback',
324
+ 'args' => array(
325
+ 'menu' => $option,
326
+ 'id' => 'my_account_restrict',
327
+ 'options' => $order_statuses,
328
+ ),
329
+ ),
330
+ )
331
+ );
332
+
333
+ add_settings_field(
334
+ 'invoice_number_column',
335
+ __( 'Enable invoice number column in the orders list', 'wpo_wcpdf' ),
336
+ array( &$this, 'checkbox_element_callback' ),
337
+ $option,
338
+ 'interface',
339
+ array(
340
+ 'menu' => $option,
341
+ 'id' => 'invoice_number_column',
342
+ )
343
+ );
344
+
345
+ // Register settings.
346
+ register_setting( $option, $option, array( &$this, 'validate_options' ) );
347
+
348
+ $option_values = get_option($option);
349
+ // convert old 'statusless' setting to new status array
350
+ if ( isset( $option_values['email_pdf'] ) && !is_array( $option_values['email_pdf'] ) ) {
351
+ $default_status = apply_filters( 'wpo_wcpdf_attach_to_status', 'completed' );
352
+ $option_values['email_pdf'] = array (
353
+ $default_status => 1,
354
+ 'customer_invoice' => 1,
355
+ );
356
+ update_option( $option, $option_values );
357
+ }
358
+
359
+ /**************************************/
360
+ /********** TEMPLATE SETTINGS *********/
361
+ /**************************************/
362
+
363
+ $option = 'wpo_wcpdf_template_settings';
364
+
365
+ // Create option in wp_options.
366
+ if ( false === get_option( $option ) ) {
367
+ $this->default_settings( $option );
368
+ }
369
+
370
+ // Section.
371
+ add_settings_section(
372
+ 'template_settings',
373
+ __( 'PDF Template settings', 'wpo_wcpdf' ),
374
+ array( &$this, 'section_options_callback' ),
375
+ $option
376
+ );
377
+
378
+
379
+ $theme_path = get_stylesheet_directory() . '/' . $wpo_wcpdf->export->template_base_path;
380
+ $theme_template_path = substr($theme_path, strpos($theme_path, 'wp-content')) . 'yourtemplate';
381
+ $plugin_template_path = 'wp-content/plugins/woocommerce-pdf-invoices-packing-slips/templates/pdf/Simple';
382
+
383
+ add_settings_field(
384
+ 'template_path',
385
+ __( 'Choose a template', 'wpo_wcpdf' ),
386
+ array( &$this, 'template_select_element_callback' ),
387
+ $option,
388
+ 'template_settings',
389
+ array(
390
+ 'menu' => $option,
391
+ 'id' => 'template_path',
392
+ 'options' => $this->find_templates(),
393
+ 'description' => sprintf( __( 'Want to use your own template? Copy all the files from <code>%s</code> to your (child) theme in <code>%s</code> to customize them' , 'wpo_wcpdf' ), $plugin_template_path, $theme_template_path),
394
+ )
395
+ );
396
+
397
+ add_settings_field(
398
+ 'paper_size',
399
+ __( 'Paper size', 'wpo_wcpdf' ),
400
+ array( &$this, 'select_element_callback' ),
401
+ $option,
402
+ 'template_settings',
403
+ array(
404
+ 'menu' => $option,
405
+ 'id' => 'paper_size',
406
+ 'options' => apply_filters( 'wpo_wcpdf_template_settings_paper_size', array(
407
+ 'a4' => __( 'A4' , 'wpo_wcpdf' ),
408
+ 'letter' => __( 'Letter' , 'wpo_wcpdf' ),
409
+ ) ),
410
+ )
411
+ );
412
+
413
+ add_settings_field(
414
+ 'header_logo',
415
+ __( 'Shop header/logo', 'wpo_wcpdf' ),
416
+ array( &$this, 'media_upload_callback' ),
417
+ $option,
418
+ 'template_settings',
419
+ array(
420
+ 'menu' => $option,
421
+ 'id' => 'header_logo',
422
+ 'uploader_title' => __( 'Select or upload your invoice header/logo', 'wpo_wcpdf' ),
423
+ 'uploader_button_text' => __( 'Set image', 'wpo_wcpdf' ),
424
+ 'remove_button_text' => __( 'Remove image', 'wpo_wcpdf' ),
425
+ //'description' => __( '...', 'wpo_wcpdf' ),
426
+ )
427
+ );
428
+
429
+ add_settings_field(
430
+ 'shop_name',
431
+ __( 'Shop Name', 'wpo_wcpdf' ),
432
+ array( &$this, 'text_element_callback' ),
433
+ $option,
434
+ 'template_settings',
435
+ array(
436
+ 'menu' => $option,
437
+ 'id' => 'shop_name',
438
+ 'size' => '72',
439
+ 'translatable' => true,
440
+ )
441
+ );
442
+
443
+ add_settings_field(
444
+ 'shop_address',
445
+ __( 'Shop Address', 'wpo_wcpdf' ),
446
+ array( &$this, 'textarea_element_callback' ),
447
+ $option,
448
+ 'template_settings',
449
+ array(
450
+ 'menu' => $option,
451
+ 'id' => 'shop_address',
452
+ 'width' => '72',
453
+ 'height' => '8',
454
+ 'translatable' => true,
455
+ //'description' => __( '...', 'wpo_wcpdf' ),
456
+ )
457
+ );
458
+
459
+ add_settings_field(
460
+ 'footer',
461
+ __( 'Footer: terms & conditions, policies, etc.', 'wpo_wcpdf' ),
462
+ array( &$this, 'textarea_element_callback' ),
463
+ $option,
464
+ 'template_settings',
465
+ array(
466
+ 'menu' => $option,
467
+ 'id' => 'footer',
468
+ 'width' => '72',
469
+ 'height' => '4',
470
+ 'translatable' => true,
471
+ //'description' => __( '...', 'wpo_wcpdf' ),
472
+ )
473
+ );
474
+
475
+ // Section.
476
+ add_settings_section(
477
+ 'invoice',
478
+ __( 'Invoice', 'wpo_wcpdf' ),
479
+ array( &$this, 'section_options_callback' ),
480
+ $option
481
+ );
482
+
483
+ add_settings_field(
484
+ 'invoice_shipping_address',
485
+ __( 'Display shipping address', 'wpo_wcpdf' ),
486
+ array( &$this, 'checkbox_element_callback' ),
487
+ $option,
488
+ 'invoice',
489
+ array(
490
+ 'menu' => $option,
491
+ 'id' => 'invoice_shipping_address',
492
+ 'description' => __( 'Display shipping address on invoice (in addition to the default billing address) if different from billing address', 'wpo_wcpdf' ),
493
+ )
494
+ );
495
+
496
+ add_settings_field(
497
+ 'invoice_email',
498
+ __( 'Display email address', 'wpo_wcpdf' ),
499
+ array( &$this, 'checkbox_element_callback' ),
500
+ $option,
501
+ 'invoice',
502
+ array(
503
+ 'menu' => $option,
504
+ 'id' => 'invoice_email',
505
+ )
506
+ );
507
+
508
+ add_settings_field(
509
+ 'invoice_phone',
510
+ __( 'Display phone number', 'wpo_wcpdf' ),
511
+ array( &$this, 'checkbox_element_callback' ),
512
+ $option,
513
+ 'invoice',
514
+ array(
515
+ 'menu' => $option,
516
+ 'id' => 'invoice_phone',
517
+ )
518
+ );
519
+
520
+ add_settings_field(
521
+ 'display_date',
522
+ __( 'Display invoice date', 'wpo_wcpdf' ),
523
+ array( &$this, 'checkbox_element_callback' ),
524
+ $option,
525
+ 'invoice',
526
+ array(
527
+ 'menu' => $option,
528
+ 'id' => 'display_date',
529
+ 'value' => 'invoice_date',
530
+ )
531
+ );
532
+
533
+ add_settings_field(
534
+ 'display_number',
535
+ __( 'Display built-in sequential invoice number', 'wpo_wcpdf' ),
536
+ array( &$this, 'checkbox_element_callback' ),
537
+ $option,
538
+ 'invoice',
539
+ array(
540
+ 'menu' => $option,
541
+ 'id' => 'display_number',
542
+ 'value' => 'invoice_number',
543
+ )
544
+ );
545
+
546
+ // invoice number is stored separately for direct retrieval
547
+ register_setting( $option, 'wpo_wcpdf_next_invoice_number', array( &$this, 'validate_options' ) );
548
+ add_settings_field(
549
+ 'next_invoice_number',
550
+ __( 'Next invoice number (without prefix/suffix etc.)', 'wpo_wcpdf' ),
551
+ array( &$this, 'singular_text_element_callback' ),
552
+ $option,
553
+ 'invoice',
554
+ array(
555
+ 'menu' => 'wpo_wcpdf_next_invoice_number',
556
+ 'id' => 'next_invoice_number',
557
+ 'size' => '10',
558
+ 'description' => __( 'This is the number that will be used on the next invoice that is created. By default, numbering starts from the WooCommerce Order Number of the first invoice that is created and increases for every new invoice. Note that if you override this and set it lower than the highest (PDF) invoice number, this could create double invoice numbers!', 'wpo_wcpdf' ),
559
+ )
560
+ );
561
+
562
+ // first time invoice number
563
+ $next_invoice_number = get_option('wpo_wcpdf_next_invoice_number');
564
+ // determine highest invoice number if option not set
565
+ if ( !isset( $next_invoice_number ) ) {
566
+ // Based on code from WooCommerce Sequential Order Numbers
567
+ global $wpdb;
568
+ // get highest invoice_number in postmeta table
569
+ $max_invoice_number = $wpdb->get_var( 'SELECT max(cast(meta_value as UNSIGNED)) from ' . $wpdb->postmeta . ' where meta_key="_wcpdf_invoice_number"' );
570
+
571
+ if ( !empty($max_invoice_number) ) {
572
+ $next_invoice_number = $max_invoice_number+1;
573
+ } else {
574
+ $next_invoice_number = '';
575
+ }
576
+
577
+ update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
578
+ }
579
+
580
+ add_settings_field(
581
+ 'invoice_number_formatting',
582
+ __( 'Invoice number format', 'wpo_wcpdf' ),
583
+ array( &$this, 'invoice_number_formatting_callback' ),
584
+ $option,
585
+ 'invoice',
586
+ array(
587
+ 'menu' => $option,
588
+ 'id' => 'invoice_number_formatting',
589
+ 'fields' => array(
590
+ 'prefix' => array(
591
+ 'title' => __( 'Prefix' , 'wpo_wcpdf' ),
592
+ 'size' => 20,
593
+ 'description' => __( 'to use the invoice year and/or month, use [invoice_year] or [invoice_month] respectively' , 'wpo_wcpdf' ),
594
+ ),
595
+ 'suffix' => array(
596
+ 'title' => __( 'Suffix' , 'wpo_wcpdf' ),
597
+ 'size' => 20,
598
+ 'description' => '',
599
+ ),
600
+ 'padding' => array(
601
+ 'title' => __( 'Padding' , 'wpo_wcpdf' ),
602
+ 'size' => 2,
603
+ 'description' => __( 'enter the number of digits here - enter "6" to display 42 as 000042' , 'wpo_wcpdf' ),
604
+ ),
605
+ ),
606
+ 'description' => __( 'note: if you have already created a custom invoice number format with a filter, the above settings will be ignored' , 'wpo_wcpdf' ),
607
+ )
608
+ );
609
+
610
+ add_settings_field(
611
+ 'yearly_reset_invoice_number',
612
+ __( 'Reset invoice number yearly', 'wpo_wcpdf' ),
613
+ array( &$this, 'checkbox_element_callback' ),
614
+ $option,
615
+ 'invoice',
616
+ array(
617
+ 'menu' => $option,
618
+ 'id' => 'yearly_reset_invoice_number',
619
+ )
620
+ );
621
+
622
+ add_settings_field(
623
+ 'currency_font',
624
+ __( 'Extended currency symbol support', 'wpo_wcpdf' ),
625
+ array( &$this, 'checkbox_element_callback' ),
626
+ $option,
627
+ 'invoice',
628
+ array(
629
+ 'menu' => $option,
630
+ 'id' => 'currency_font',
631
+ 'description' => __( 'Enable this if your currency symbol is not displaying properly' , 'wpo_wcpdf' ),
632
+ )
633
+ );
634
+
635
+ // Section.
636
+ add_settings_section(
637
+ 'packing_slip',
638
+ __( 'Packing Slip', 'wpo_wcpdf' ),
639
+ array( &$this, 'section_options_callback' ),
640
+ $option
641
+ );
642
+
643
+ add_settings_field(
644
+ 'packing_slip_billing_address',
645
+ __( 'Display billing address', 'wpo_wcpdf' ),
646
+ array( &$this, 'checkbox_element_callback' ),
647
+ $option,
648
+ 'packing_slip',
649
+ array(
650
+ 'menu' => $option,
651
+ 'id' => 'packing_slip_billing_address',
652
+ 'description' => __( 'Display billing address on packing slip (in addition to the default shipping address) if different from shipping address', 'wpo_wcpdf' ),
653
+ )
654
+ );
655
+
656
+ add_settings_field(
657
+ 'packing_slip_email',
658
+ __( 'Display email address', 'wpo_wcpdf' ),
659
+ array( &$this, 'checkbox_element_callback' ),
660
+ $option,
661
+ 'packing_slip',
662
+ array(
663
+ 'menu' => $option,
664
+ 'id' => 'packing_slip_email',
665
+ )
666
+ );
667
+
668
+ add_settings_field(
669
+ 'packing_slip_phone',
670
+ __( 'Display phone number', 'wpo_wcpdf' ),
671
+ array( &$this, 'checkbox_element_callback' ),
672
+ $option,
673
+ 'packing_slip',
674
+ array(
675
+ 'menu' => $option,
676
+ 'id' => 'packing_slip_phone',
677
+ )
678
+ );
679
+
680
+ // Section.
681
+ add_settings_section(
682
+ 'extra_template_fields',
683
+ __( 'Extra template fields', 'wpo_wcpdf' ),
684
+ array( &$this, 'custom_fields_section' ),
685
+ $option
686
+ );
687
+
688
+ add_settings_field(
689
+ 'extra_1',
690
+ __( 'Extra field 1', 'wpo_wcpdf' ),
691
+ array( &$this, 'textarea_element_callback' ),
692
+ $option,
693
+ 'extra_template_fields',
694
+ array(
695
+ 'menu' => $option,
696
+ 'id' => 'extra_1',
697
+ 'width' => '72',
698
+ 'height' => '8',
699
+ 'description' => __( 'This is footer column 1 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
700
+ 'translatable' => true,
701
+ )
702
+ );
703
+
704
+ add_settings_field(
705
+ 'extra_2',
706
+ __( 'Extra field 2', 'wpo_wcpdf' ),
707
+ array( &$this, 'textarea_element_callback' ),
708
+ $option,
709
+ 'extra_template_fields',
710
+ array(
711
+ 'menu' => $option,
712
+ 'id' => 'extra_2',
713
+ 'width' => '72',
714
+ 'height' => '8',
715
+ 'description' => __( 'This is footer column 2 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
716
+ 'translatable' => true,
717
+ )
718
+ );
719
+
720
+ add_settings_field(
721
+ 'extra_3',
722
+ __( 'Extra field 3', 'wpo_wcpdf' ),
723
+ array( &$this, 'textarea_element_callback' ),
724
+ $option,
725
+ 'extra_template_fields',
726
+ array(
727
+ 'menu' => $option,
728
+ 'id' => 'extra_3',
729
+ 'width' => '72',
730
+ 'height' => '8',
731
+ 'description' => __( 'This is footer column 3 in the <i>Modern (Premium)</i> template', 'wpo_wcpdf' ),
732
+ 'translatable' => true,
733
+ )
734
+ );
735
+
736
+ // Register settings.
737
+ register_setting( $option, $option, array( &$this, 'validate_options' ) );
738
+
739
+ /**************************************/
740
+ /******** DEBUG/STATUS SETTINGS *******/
741
+ /**************************************/
742
+
743
+ $option = 'wpo_wcpdf_debug_settings';
744
+
745
+ // Create option in wp_options.
746
+ if ( false === get_option( $option ) ) {
747
+ $this->default_settings( $option );
748
+ }
749
+
750
+ // Section.
751
+ add_settings_section(
752
+ 'debug_settings',
753
+ __( 'Debug settings', 'wpo_wcpdf' ),
754
+ array( &$this, 'debug_section' ),
755
+ $option
756
+ );
757
+
758
+ add_settings_field(
759
+ 'enable_debug',
760
+ __( 'Enable debug output', 'wpo_wcpdf' ),
761
+ array( &$this, 'checkbox_element_callback' ),
762
+ $option,
763
+ 'debug_settings',
764
+ array(
765
+ 'menu' => $option,
766
+ 'id' => 'enable_debug',
767
+ 'description' => __( "Enable this option to output plugin errors if you're getting a blank page or other PDF generation issues", 'wpo_wcpdf' ),
768
+ )
769
+ );
770
+
771
+ add_settings_field(
772
+ 'html_output',
773
+ __( 'Output to HTML', 'wpo_wcpdf' ),
774
+ array( &$this, 'checkbox_element_callback' ),
775
+ $option,
776
+ 'debug_settings',
777
+ array(
778
+ 'menu' => $option,
779
+ 'id' => 'html_output',
780
+ 'description' => __( 'Send the template output as HTML to the browser instead of creating a PDF.', 'wpo_wcpdf' ),
781
+ )
782
+ );
783
+
784
+ add_settings_field(
785
+ 'old_tmp',
786
+ __( 'Use old tmp folder', 'wpo_wcpdf' ),
787
+ array( &$this, 'checkbox_element_callback' ),
788
+ $option,
789
+ 'debug_settings',
790
+ array(
791
+ 'menu' => $option,
792
+ 'id' => 'old_tmp',
793
+ 'description' => __( 'Before version 1.5 of PDF Invoices, temporary files were stored in the plugin folder. This setting is only intended for backwards compatibility, not recommended on new installs!', 'wpo_wcpdf' ),
794
+ )
795
+ );
796
+
797
+ // Register settings.
798
+ register_setting( $option, $option, array( &$this, 'validate_options' ) );
799
+
800
+ }
801
+
802
+ /**
803
+ * get all emails registered in WooCommerce
804
+ * @param boolean $remove_defaults switch to remove default woocommerce emails
805
+ * @return array $emails list of all email ids/slugs and names
806
+ */
807
+ public function get_wc_emails ( $remove_defaults = true ) {
808
+ // get emails from WooCommerce
809
+ global $woocommerce;
810
+ $mailer = $woocommerce->mailer();
811
+ $wc_emails = $mailer->get_emails();
812
+
813
+ $default_emails = array(
814
+ 'new_order',
815
+ 'customer_processing_order',
816
+ 'customer_completed_order',
817
+ 'customer_invoice',
818
+ 'customer_note',
819
+ 'customer_reset_password',
820
+ 'customer_new_account'
821
+ );
822
+
823
+ $emails = array();
824
+ foreach ($wc_emails as $name => $template) {
825
+ if ( !( $remove_defaults && in_array( $template->id, $default_emails ) ) ) {
826
+ $emails[$template->id] = $template->title;
827
+ }
828
+ }
829
+
830
+ return $emails;
831
+ }
832
+
833
+ /**
834
+ * WooCommerce Order Status & Actions Manager emails compatibility
835
+ */
836
+ public function wc_order_status_actions_emails ( $emails ) {
837
+ // check if WC_Custom_Status class is loaded!
838
+ if (class_exists('WC_Custom_Status')) {
839
+ // get list of custom statuses from WooCommerce Custom Order Status & Actions
840
+ // status slug => status name
841
+ $custom_statuses = WC_Custom_Status::get_status_list_names();
842
+ // append _email to slug (=email_id) and add to emails list
843
+ foreach ($custom_statuses as $status_slug => $status_name) {
844
+ $emails[$status_slug.'_email'] = $status_name;
845
+ }
846
+ }
847
+ return $emails;
848
+ }
849
+
850
+ /**
851
+ * Set default settings.
852
+ */
853
+ public function default_settings( $option ) {
854
+ global $wpo_wcpdf;
855
+
856
+ switch ( $option ) {
857
+ case 'wpo_wcpdf_general_settings':
858
+ $default = array(
859
+ 'download_display' => 'download',
860
+ );
861
+ break;
862
+ case 'wpo_wcpdf_template_settings':
863
+ $default = array(
864
+ 'paper_size' => 'a4',
865
+ 'template_path' => $wpo_wcpdf->export->template_default_base_path . 'Simple',
866
+ // 'invoice_shipping_address' => '1',
867
+ );
868
+ break;
869
+ default:
870
+ $default = array();
871
+ break;
872
+ }
873
+
874
+ if ( false === get_option( $option ) ) {
875
+ add_option( $option, $default );
876
+ } else {
877
+ update_option( $option, $default );
878
+
879
+ }
880
+ }
881
+
882
+ // Text element callback.
883
+ public function text_element_callback( $args ) {
884
+ $menu = $args['menu'];
885
+ $id = $args['id'];
886
+ $size = isset( $args['size'] ) ? $args['size'] : '25';
887
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
888
+
889
+ $options = get_option( $menu );
890
+
891
+ if ( isset( $options[$id] ) ) {
892
+ $current = $options[$id];
893
+ } else {
894
+ $current = isset( $args['default'] ) ? $args['default'] : '';
895
+ }
896
+
897
+ $html = sprintf( '<input type="text" id="%1$s" name="%2$s[%1$s]" value="%3$s" size="%4$s" class="%5$s"/>', $id, $menu, $current, $size, $class );
898
+
899
+ // Displays option description.
900
+ if ( isset( $args['description'] ) ) {
901
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
902
+ }
903
+
904
+ echo $html;
905
+ }
906
+
907
+ // Single text option (not part of any settings array)
908
+ public function singular_text_element_callback( $args ) {
909
+ $menu = $args['menu'];
910
+ $id = $args['id'];
911
+ $size = isset( $args['size'] ) ? $args['size'] : '25';
912
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
913
+
914
+ $option = get_option( $menu );
915
+
916
+ if ( isset( $option ) ) {
917
+ $current = $option;
918
+ } else {
919
+ $current = isset( $args['default'] ) ? $args['default'] : '';
920
+ }
921
+
922
+ $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $menu, $current, $size, $class );
923
+
924
+ // Displays option description.
925
+ if ( isset( $args['description'] ) ) {
926
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
927
+ }
928
+
929
+ echo $html;
930
+ }
931
+
932
+ // Text element callback.
933
+ public function textarea_element_callback( $args ) {
934
+ $menu = $args['menu'];
935
+ $id = $args['id'];
936
+ $width = $args['width'];
937
+ $height = $args['height'];
938
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
939
+
940
+ $options = get_option( $menu );
941
+
942
+ if ( isset( $options[$id] ) ) {
943
+ $current = $options[$id];
944
+ } else {
945
+ $current = isset( $args['default'] ) ? $args['default'] : '';
946
+ }
947
+
948
+ $html = sprintf( '<textarea id="%1$s" name="%2$s[%1$s]" cols="%4$s" rows="%5$s" class="%6$s"/>%3$s</textarea>', $id, $menu, $current, $width, $height, $class );
949
+
950
+ // Displays option description.
951
+ if ( isset( $args['description'] ) ) {
952
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
953
+ }
954
+
955
+ echo $html;
956
+ }
957
+
958
+
959
+ /**
960
+ * Checkbox field callback.
961
+ *
962
+ * @param array $args Field arguments.
963
+ *
964
+ * @return string Checkbox field.
965
+ */
966
+ public function checkbox_element_callback( $args ) {
967
+ $menu = $args['menu'];
968
+ $id = $args['id'];
969
+ $value = isset( $args['value'] ) ? $args['value'] : 1;
970
+
971
+ $options = get_option( $menu );
972
+
973
+ if ( isset( $options[$id] ) ) {
974
+ $current = $options[$id];
975
+ } else {
976
+ $current = isset( $args['default'] ) ? $args['default'] : '';
977
+ }
978
+
979
+ $html = sprintf( '<input type="checkbox" id="%1$s" name="%2$s[%1$s]" value="%3$s"%4$s />', $id, $menu, $value, checked( $value, $current, false ) );
980
+
981
+ // Displays option description.
982
+ if ( isset( $args['description'] ) ) {
983
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
984
+ }
985
+
986
+ echo $html;
987
+ }
988
+
989
+ /**
990
+ * Multiple Checkbox field callback.
991
+ *
992
+ * @param array $args Field arguments.
993
+ *
994
+ * @return string Checkbox field.
995
+ */
996
+ public function multiple_checkbox_element_callback( $args ) {
997
+ $menu = $args['menu'];
998
+ $id = $args['id'];
999
+
1000
+ $options = get_option( $menu );
1001
+
1002
+
1003
+ foreach ( $args['options'] as $key => $label ) {
1004
+ $current = ( isset( $options[$id][$key] ) ) ? $options[$id][$key] : '';
1005
+ printf( '<input type="checkbox" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="1"%4$s /> %5$s<br/>', $menu, $id, $key, checked( 1, $current, false ), $label );
1006
+ }
1007
+
1008
+ // Displays option description.
1009
+ if ( isset( $args['description'] ) ) {
1010
+ printf( '<p class="description">%s</p>', $args['description'] );
1011
+ }
1012
+ }
1013
+
1014
+ /**
1015
+ * Checkbox fields table callback.
1016
+ *
1017
+ * @param array $args Field arguments.
1018
+ *
1019
+ * @return string Checkbox field.
1020
+ */
1021
+ public function checkbox_table_callback( $args ) {
1022
+ $menu = $args['menu'];
1023
+ $id = $args['id'];
1024
+
1025
+ $options = get_option( $menu );
1026
+
1027
+ $rows = $args['rows'];
1028
+ $columns = $args['columns'];
1029
+
1030
+ ?>
1031
+ <table style="">
1032
+ <tr>
1033
+ <td style="padding:0 10px 5px 0;">&nbsp;</td>
1034
+ <?php foreach ( $columns as $column => $title ) { ?>
1035
+ <td style="padding:0 10px 5px 0;"><?php echo $title; ?></td>
1036
+ <?php } ?>
1037
+ </tr>
1038
+ <tr>
1039
+ <td style="padding: 0;">
1040
+ <?php foreach ($rows as $row) {
1041
+ echo $row.'<br/>';
1042
+ } ?>
1043
+ </td>
1044
+ <?php foreach ( $columns as $column => $title ) { ?>
1045
+ <td style="text-align:center; padding: 0;">
1046
+ <?php foreach ( $rows as $row => $title ) {
1047
+ $current = ( isset( $options[$id.'_'.$column][$row] ) ) ? $options[$id.'_'.$column][$row] : '';
1048
+ $name = sprintf('%1$s[%2$s_%3$s][%4$s]', $menu, $id, $column, $row);
1049
+ printf( '<input type="checkbox" id="%1$s" name="%1$s" value="1"%2$s /><br/>', $name, checked( 1, $current, false ) );
1050
+ } ?>
1051
+ </td>
1052
+ <?php } ?>
1053
+ </tr>
1054
+ </table>
1055
+
1056
+ <?php
1057
+ // Displays option description.
1058
+ if ( isset( $args['description'] ) ) {
1059
+ printf( '<p class="description">%s</p>', $args['description'] );
1060
+ }
1061
+ }
1062
+
1063
+ /**
1064
+ * Select element callback.
1065
+ *
1066
+ * @param array $args Field arguments.
1067
+ *
1068
+ * @return string Select field.
1069
+ */
1070
+ public function select_element_callback( $args ) {
1071
+ $menu = $args['menu'];
1072
+ $id = $args['id'];
1073
+
1074
+ $options = get_option( $menu );
1075
+
1076
+ if ( isset( $options[$id] ) ) {
1077
+ $current = $options[$id];
1078
+ } else {
1079
+ $current = isset( $args['default'] ) ? $args['default'] : '';
1080
+ }
1081
+
1082
+ printf( '<select id="%1$s" name="%2$s[%1$s]">', $id, $menu );
1083
+
1084
+ foreach ( $args['options'] as $key => $label ) {
1085
+ printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
1086
+ }
1087
+
1088
+ echo '</select>';
1089
+
1090
+
1091
+ if (isset($args['custom'])) {
1092
+ $custom = $args['custom'];
1093
+
1094
+ $custom_id = $id.'_custom';
1095
+
1096
+ printf( '<br/><br/><div id="%s" style="display:none;">', $custom_id );
1097
+
1098
+ switch ($custom['type']) {
1099
+ case 'text_element_callback':
1100
+ $this->text_element_callback( $custom['args'] );
1101
+ break;
1102
+ case 'multiple_text_element_callback':
1103
+ $this->multiple_text_element_callback( $custom['args'] );
1104
+ break;
1105
+ case 'multiple_checkbox_element_callback':
1106
+ $this->multiple_checkbox_element_callback( $custom['args'] );
1107
+ break;
1108
+ default:
1109
+ break;
1110
+ }
1111
+
1112
+ echo '</div>';
1113
+
1114
+ ?>
1115
+ <script type="text/javascript">
1116
+ jQuery(document).ready(function($) {
1117
+ function check_<?php echo $id; ?>_custom() {
1118
+ var custom = $('#<?php echo $id; ?>').val();
1119
+ if (custom == 'custom') {
1120
+ $( '#<?php echo $custom_id; ?>').show();
1121
+ } else {
1122
+ $( '#<?php echo $custom_id; ?>').hide();
1123
+ }
1124
+ }
1125
+
1126
+ check_<?php echo $id; ?>_custom();
1127
+
1128
+ $( '#<?php echo $id; ?>' ).change(function() {
1129
+ check_<?php echo $id; ?>_custom();
1130
+ });
1131
+
1132
+ });
1133
+ </script>
1134
+ <?php
1135
+ }
1136
+
1137
+ // Displays option description.
1138
+ if ( isset( $args['description'] ) ) {
1139
+ printf( '<p class="description">%s</p>', $args['description'] );
1140
+ }
1141
+
1142
+ }
1143
+
1144
+ /**
1145
+ * Displays a radio settings field
1146
+ *
1147
+ * @param array $args settings field args
1148
+ */
1149
+ public function radio_element_callback( $args ) {
1150
+ $menu = $args['menu'];
1151
+ $id = $args['id'];
1152
+
1153
+ $options = get_option( $menu );
1154
+
1155
+ if ( isset( $options[$id] ) ) {
1156
+ $current = $options[$id];
1157
+ } else {
1158
+ $current = isset( $args['default'] ) ? $args['default'] : '';
1159
+ }
1160
+
1161
+ $html = '';
1162
+ foreach ( $args['options'] as $key => $label ) {
1163
+ $html .= sprintf( '<input type="radio" class="radio" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s"%4$s />', $menu, $id, $key, checked( $current, $key, false ) );
1164
+ $html .= sprintf( '<label for="%1$s[%2$s][%3$s]"> %4$s</label><br>', $menu, $id, $key, $label);
1165
+ }
1166
+
1167
+ // Displays option description.
1168
+ if ( isset( $args['description'] ) ) {
1169
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1170
+ }
1171
+
1172
+ echo $html;
1173
+ }
1174
+
1175
+ /**
1176
+ * Media upload callback.
1177
+ *
1178
+ * @param array $args Field arguments.
1179
+ *
1180
+ * @return string Media upload button & preview.
1181
+ */
1182
+ public function media_upload_callback( $args ) {
1183
+ $menu = $args['menu'];
1184
+ $id = $args['id'];
1185
+ $options = get_option( $menu );
1186
+
1187
+ if ( isset( $options[$id] ) ) {
1188
+ $current = $options[$id];
1189
+ } else {
1190
+ $current = isset( $args['default'] ) ? $args['default'] : '';
1191
+ }
1192
+
1193
+ $uploader_title = $args['uploader_title'];
1194
+ $uploader_button_text = $args['uploader_button_text'];
1195
+ $remove_button_text = $args['remove_button_text'];
1196
+
1197
+ $html = '';
1198
+ if( !empty($current) ) {
1199
+ $attachment = wp_get_attachment_image_src( $current, 'full', false );
1200
+
1201
+ $attachment_src = $attachment[0];
1202
+ $attachment_width = $attachment[1];
1203
+ $attachment_height = $attachment[2];
1204
+
1205
+ $attachment_resolution = round($attachment_height/(3/2.54));
1206
+
1207
+ $html .= sprintf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
1208
+ $html .= '<div class="attachment-resolution"><p class="description">'.__('Image resolution').': '.$attachment_resolution.'dpi (default height = 3cm)</p></div>';
1209
+ $html .= sprintf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
1210
+ }
1211
+
1212
+ $html .= sprintf( '<input id="%1$s" name="%2$s[%1$s]" type="hidden" value="%3$s" />', $id, $menu, $current );
1213
+
1214
+ $html .= sprintf( '<span class="button wpo_upload_image_button %4$s" data-uploader_title="%1$s" data-uploader_button_text="%2$s" data-remove_button_text="%3$s" data-input_id="%4$s">%2$s</span>', $uploader_title, $uploader_button_text, $remove_button_text, $id );
1215
+
1216
+ // Displays option description.
1217
+ if ( isset( $args['description'] ) ) {
1218
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1219
+ }
1220
+
1221
+ echo $html;
1222
+ }
1223
+
1224
+ /**
1225
+ * Invoice number formatting callback.
1226
+ *
1227
+ * @param array $args Field arguments.
1228
+ *
1229
+ * @return string Media upload button & preview.
1230
+ */
1231
+ public function invoice_number_formatting_callback( $args ) {
1232
+ $menu = $args['menu'];
1233
+ $fields = $args['fields'];
1234
+ $options = get_option( $menu );
1235
+
1236
+ echo '<table>';
1237
+ foreach ($fields as $key => $field) {
1238
+ $id = $args['id'] . '_' . $key;
1239
+
1240
+ if ( isset( $options[$id] ) ) {
1241
+ $current = $options[$id];
1242
+ } else {
1243
+ $current = '';
1244
+ }
1245
+
1246
+ $title = $field['title'];
1247
+ $size = $field['size'];
1248
+ $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
1249
+
1250
+ echo '<tr>';
1251
+ printf( '<td style="padding:0 1em 0 0; ">%1$s:</td><td style="padding:0;"><input type="text" id="%2$s" name="%3$s[%2$s]" value="%4$s" size="%5$s"/></td><td style="padding:0 0 0 1em;">%6$s</td>', $title, $id, $menu, $current, $size, $description );
1252
+ echo '</tr>';
1253
+ }
1254
+ echo '</table>';
1255
+
1256
+
1257
+ // Displays option description.
1258
+ if ( isset( $args['description'] ) ) {
1259
+ printf( '<p class="description">%s</p>', $args['description'] );
1260
+ }
1261
+
1262
+ // echo $html;
1263
+ }
1264
+
1265
+
1266
+ /**
1267
+ * Template select element callback.
1268
+ *
1269
+ * @param array $args Field arguments.
1270
+ *
1271
+ * @return string Select field.
1272
+ */
1273
+ public function template_select_element_callback( $args ) {
1274
+ $menu = $args['menu'];
1275
+ $id = $args['id'];
1276
+
1277
+ $options = get_option( $menu );
1278
+
1279
+ if ( isset( $options[$id] ) ) {
1280
+ $current = $options[$id];
1281
+ } else {
1282
+ $current = isset( $args['default'] ) ? $args['default'] : '';
1283
+ }
1284
+
1285
+ $html = sprintf( '<select id="%1$s" name="%2$s[%1$s]">', $id, $menu );
1286
+
1287
+ // backwards compatible template path (1.4.4+ uses relative paths instead of absolute)
1288
+ if (strpos($current, ABSPATH) !== false) {
1289
+ // check if folder exists, then strip site base path.
1290
+ if ( file_exists( $current ) ) {
1291
+ $current = str_replace( ABSPATH, '', $current );
1292
+ }
1293
+ }
1294
+
1295
+ foreach ( $args['options'] as $key => $label ) {
1296
+ $html .= sprintf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
1297
+ }
1298
+
1299
+ $html .= '</select>';
1300
+
1301
+ // Displays option description.
1302
+ if ( isset( $args['description'] ) ) {
1303
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
1304
+ }
1305
+
1306
+ echo $html;
1307
+
1308
+ }
1309
+
1310
+ /**
1311
+ * Section null callback.
1312
+ *
1313
+ * @return void.
1314
+ */
1315
+ public function section_options_callback() {
1316
+ }
1317
+
1318
+ /**
1319
+ * Debug section callback.
1320
+ *
1321
+ * @return void.
1322
+ */
1323
+ public function debug_section() {
1324
+ _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'wpo_wcpdf' );
1325
+ }
1326
+
1327
+ /**
1328
+ * Custom fields section callback.
1329
+ *
1330
+ * @return void.
1331
+ */
1332
+ public function custom_fields_section() {
1333
+ _e( 'These are used for the (optional) footer columns in the <em>Modern (Premium)</em> template, but can also be used for other elements in your custom template' , 'wpo_wcpdf' );
1334
+ }
1335
+
1336
+ /**
1337
+ * Validate options.
1338
+ *
1339
+ * @param array $input options to valid.
1340
+ *
1341
+ * @return array validated options.
1342
+ */
1343
+ public function validate_options( $input ) {
1344
+ // Create our array for storing the validated options.
1345
+ $output = array();
1346
+
1347
+ if (empty($input) || !is_array($input)) {
1348
+ return $input;
1349
+ }
1350
+
1351
+ // Loop through each of the incoming options.
1352
+ foreach ( $input as $key => $value ) {
1353
+
1354
+ // Check to see if the current option has a value. If so, process it.
1355
+ if ( isset( $input[$key] ) ) {
1356
+ if ( is_array( $input[$key] ) ) {
1357
+ foreach ( $input[$key] as $sub_key => $sub_value ) {
1358
+ $output[$key][$sub_key] = $input[$key][$sub_key];
1359
+ }
1360
+ } else {
1361
+ $output[$key] = $input[$key];
1362
+ }
1363
+ }
1364
+ }
1365
+
1366
+ // Return the array processing any additional functions filtered by this action.
1367
+ return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
1368
+ }
1369
+
1370
+ /**
1371
+ * List templates in plugin folder, theme folder & child theme folder
1372
+ * @return array template path => template name
1373
+ */
1374
+ public function find_templates() {
1375
+ global $wpo_wcpdf;
1376
+ $installed_templates = array();
1377
+
1378
+ // get base paths
1379
+ $template_paths = array (
1380
+ // note the order: child-theme before theme, so that array_unique filters out parent doubles
1381
+ 'default' => $wpo_wcpdf->export->template_default_base_path,
1382
+ 'child-theme' => get_stylesheet_directory() . '/' . $wpo_wcpdf->export->template_base_path,
1383
+ 'theme' => get_template_directory() . '/' . $wpo_wcpdf->export->template_base_path,
1384
+ );
1385
+
1386
+ $template_paths = apply_filters( 'wpo_wcpdf_template_paths', $template_paths );
1387
+
1388
+ foreach ($template_paths as $template_source => $template_path) {
1389
+ $dirs = (array) glob( $template_path . '*' , GLOB_ONLYDIR);
1390
+
1391
+ foreach ($dirs as $dir) {
1392
+ if ( file_exists($dir."/invoice.php") && file_exists($dir."/packing-slip.php"))
1393
+ // we're stripping abspath to make the plugin settings more portable
1394
+ $installed_templates[ str_replace( ABSPATH, '', $dir )] = basename($dir);
1395
+ }
1396
+ }
1397
+
1398
+ // remove parent doubles
1399
+ $installed_templates = array_unique($installed_templates);
1400
+
1401
+ if (empty($installed_templates)) {
1402
+ // fallback to Simple template for servers with glob() disabled
1403
+ $simple_template_path = str_replace( ABSPATH, '', $template_paths['default'] . 'Simple' );
1404
+ $installed_templates[$simple_template_path] = 'Simple';
1405
+ }
1406
+
1407
+ return apply_filters( 'wpo_wcpdf_templates', $installed_templates );
1408
+ }
1409
+
1410
+ } // end class WooCommerce_PDF_Invoices_Settings
1411
+
1412
  } // end class_exists
includes/wcpdf-extensions.php CHANGED
@@ -1,100 +1,100 @@
1
- <script type="text/javascript">
2
- jQuery(document).ready(function() {
3
- jQuery('.extensions .more').hide();
4
-
5
- jQuery('.extensions > li').click(function() {
6
- jQuery(this).toggleClass('expanded');
7
- jQuery(this).find('.more').slideToggle();
8
- });
9
- });
10
- </script>
11
-
12
- <div class="wcpdf-extensions-ad">
13
-
14
- <img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/wpo-helper.png'; ?>" class="wpo-helper">
15
- <h3><?php _e( 'Check out these premium extensions!', 'wpo_wcpdf' ); ?></h3>
16
- <i>(<?php _e( 'click items to read more', 'wpo_wcpdf' ); ?>)</i>
17
- <ul class="extensions">
18
-
19
- <?php
20
- if (!class_exists('WooCommerce_PDF_IPS_Pro')) {
21
- ?>
22
- <li>
23
- <?php _e('Go Pro: Proforma invoices, credit notes (=refunds) & more!', 'wpo_wcpdf')?>
24
- <div class="more" style="display:none;">
25
- <?php _e( 'Supercharge WooCommerce PDF Invoices & Packing Slips with the following features:', 'wpo_wcpdf' ); ?>
26
- <ul>
27
- <li><?php _e( 'Email/print/download <b>PDF Credit Notes & Proforma invoices</b>', 'wpo_wcpdf' ); ?></li>
28
- <li><?php _e( 'Send out a separate <b>notification email</b> with (or without) PDF invoices/packing slips, for example to a drop-shipper or a supplier.', 'wpo_wcpdf' ); ?></li>
29
- <li><?php _e( 'Attach <b>up to 3 static files</b> (for example a terms & conditions document) to the WooCommerce emails of your choice.', 'wpo_wcpdf' ); ?></li>
30
- <li><?php _e( 'Use <b>separate numbering systems</b> and/or format for proforma invoices and credit notes or utilize the main invoice numbering system', 'wpo_wcpdf' ); ?></li>
31
- <li><?php _e( '<b>Customize</b> the <b>shipping & billing address</b> format to include additional custom fields, font sizes etc. without the need to create a custom template.', 'wpo_wcpdf' ); ?></li>
32
- <li><?php _e( 'Use the plugin in multilingual <b>WPML</b> setups', 'wpo_wcpdf' ); ?></li>
33
- </ul>
34
- <a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/" target="_blank"><?php _e("Get WooCommerce PDF Invoices & Packing Slips Professional!", 'wpo_wcpdf'); ?></a>
35
- </li>
36
- <?php } ?>
37
-
38
- <?php
39
- if (!class_exists('WooCommerce_PDF_IPS_Dropbox')) {
40
- ?>
41
- <li>
42
- <?php _e('Upload all invoices automatically to your dropbox', 'wpo_wcpdf')?>
43
- <div class="more" style="display:none;">
44
- <table>
45
- <tr>
46
- <td><img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/dropbox_logo.png'; ?>" class="dropbox-logo"></td>
47
- <td>
48
- <?php _e( 'This extension conveniently uploads all the invoices (and other pdf documents from the professional extension) that are emailed to your customers to Dropbox. The best way to keep your invoice administration up to date!', 'wpo_wcpdf' ); ?><br/>
49
- <a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-dropbox/" target="_blank"><?php _e("Get WooCommerce PDF Invoices & Packing Slips to dropbox!", 'wpo_wcpdf'); ?></a>
50
- </td>
51
- </tr>
52
- </table>
53
- </div>
54
- </li>
55
- <?php } ?>
56
-
57
- <?php
58
- if (!class_exists('WooCommerce_Ext_PrintOrders')) {
59
- ?>
60
- <li>
61
- <?php _e('Automatically send new orders or packing slips to your printer, as soon as the customer orders!', 'wpo_wcpdf')?>
62
- <div class="more" style="display:none;">
63
- <table>
64
- <tr>
65
- <td><img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/cloud-print.png'; ?>" class="cloud-logo"></td>
66
- <td>
67
- <?php _e( 'Check out the WooCommerce Automatic Order Printing extension from our partners at Simba Hosting', 'wpo_wcpdf' ); ?><br/>
68
- <a href="https://www.simbahosting.co.uk/s3/product/woocommerce-automatic-order-printing/?affiliates=2" target="_blank"><?php _e("WooCommerce Automatic Order Printing", 'wpo_wcpdf'); ?></a>
69
- </td>
70
- </tr>
71
- </table>
72
- </div>
73
- </li>
74
- <?php } ?>
75
-
76
- <?php
77
- if (!class_exists('WooCommerce_PDF_IPS_Templates')) {
78
- $template_link = '<a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/" target="_blank">wpovernight.com</a>';
79
- $email_link = '<a href="mailto:support@wpovernight.com">support@wpovernight.com</a>'
80
- ?>
81
- <li>
82
- <?php _e('Advanced, customizable templates', 'wpo_wcpdf')?>
83
- <div class="more" style="display:none;">
84
- <ul>
85
- <li><?php _e( 'Completely customize the invoice contents (prices, taxes, thumbnails) to your needs with a drag & drop customizer', 'wpo_wcpdf' ); ?></li>
86
- <li><?php _e( 'Two extra stylish premade templates (Modern & Business)', 'wpo_wcpdf' ); ?></li>
87
- <li><?php printf( __("Check out the Premium PDF Invoice & Packing Slips templates at %s.", 'wpo_wcpdf'), $template_link );?></li>
88
- <li><?php printf( __("For custom templates, contact us at %s.", 'wpo_wcpdf'), $email_link );?></li>
89
- </ul>
90
- </div>
91
- </li>
92
- <?php } ?>
93
- </ul>
94
- <?php
95
- // link to hide message when one of the premium extensions is installed
96
- if ( class_exists('WooCommerce_PDF_IPS_Pro') || class_exists('WooCommerce_PDF_IPS_Dropbox') || class_exists('WooCommerce_PDF_IPS_Templates') || class_exists('WooCommerce_Ext_PrintOrders') ) {
97
- printf('<a href="%s" style="display:inline-block; margin-top: 10px;">%s</a>', add_query_arg( 'wpo_wcpdf_hide_extensions_ad', 'true' ), __( 'Hide this message', 'wpo_wcpdf' ) );
98
- }
99
- ?>
100
  </div>
1
+ <script type="text/javascript">
2
+ jQuery(document).ready(function() {
3
+ jQuery('.extensions .more').hide();
4
+
5
+ jQuery('.extensions > li').click(function() {
6
+ jQuery(this).toggleClass('expanded');
7
+ jQuery(this).find('.more').slideToggle();
8
+ });
9
+ });
10
+ </script>
11
+
12
+ <div class="wcpdf-extensions-ad">
13
+
14
+ <img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/wpo-helper.png'; ?>" class="wpo-helper">
15
+ <h3><?php _e( 'Check out these premium extensions!', 'wpo_wcpdf' ); ?></h3>
16
+ <i>(<?php _e( 'click items to read more', 'wpo_wcpdf' ); ?>)</i>
17
+ <ul class="extensions">
18
+
19
+ <?php
20
+ if (!class_exists('WooCommerce_PDF_IPS_Pro')) {
21
+ ?>
22
+ <li>
23
+ <?php _e('Go Pro: Proforma invoices, credit notes (=refunds) & more!', 'wpo_wcpdf')?>
24
+ <div class="more" style="display:none;">
25
+ <?php _e( 'Supercharge WooCommerce PDF Invoices & Packing Slips with the following features:', 'wpo_wcpdf' ); ?>
26
+ <ul>
27
+ <li><?php _e( 'Email/print/download <b>PDF Credit Notes & Proforma invoices</b>', 'wpo_wcpdf' ); ?></li>
28
+ <li><?php _e( 'Send out a separate <b>notification email</b> with (or without) PDF invoices/packing slips, for example to a drop-shipper or a supplier.', 'wpo_wcpdf' ); ?></li>
29
+ <li><?php _e( 'Attach <b>up to 3 static files</b> (for example a terms & conditions document) to the WooCommerce emails of your choice.', 'wpo_wcpdf' ); ?></li>
30
+ <li><?php _e( 'Use <b>separate numbering systems</b> and/or format for proforma invoices and credit notes or utilize the main invoice numbering system', 'wpo_wcpdf' ); ?></li>
31
+ <li><?php _e( '<b>Customize</b> the <b>shipping & billing address</b> format to include additional custom fields, font sizes etc. without the need to create a custom template.', 'wpo_wcpdf' ); ?></li>
32
+ <li><?php _e( 'Use the plugin in multilingual <b>WPML</b> setups', 'wpo_wcpdf' ); ?></li>
33
+ </ul>
34
+ <a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/" target="_blank"><?php _e("Get WooCommerce PDF Invoices & Packing Slips Professional!", 'wpo_wcpdf'); ?></a>
35
+ </li>
36
+ <?php } ?>
37
+
38
+ <?php
39
+ if (!class_exists('WooCommerce_PDF_IPS_Dropbox')) {
40
+ ?>
41
+ <li>
42
+ <?php _e('Upload all invoices automatically to your dropbox', 'wpo_wcpdf')?>
43
+ <div class="more" style="display:none;">
44
+ <table>
45
+ <tr>
46
+ <td><img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/dropbox_logo.png'; ?>" class="dropbox-logo"></td>
47
+ <td>
48
+ <?php _e( 'This extension conveniently uploads all the invoices (and other pdf documents from the professional extension) that are emailed to your customers to Dropbox. The best way to keep your invoice administration up to date!', 'wpo_wcpdf' ); ?><br/>
49
+ <a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-dropbox/" target="_blank"><?php _e("Get WooCommerce PDF Invoices & Packing Slips to dropbox!", 'wpo_wcpdf'); ?></a>
50
+ </td>
51
+ </tr>
52
+ </table>
53
+ </div>
54
+ </li>
55
+ <?php } ?>
56
+
57
+ <?php
58
+ if (!class_exists('WooCommerce_Ext_PrintOrders')) {
59
+ ?>
60
+ <li>
61
+ <?php _e('Automatically send new orders or packing slips to your printer, as soon as the customer orders!', 'wpo_wcpdf')?>
62
+ <div class="more" style="display:none;">
63
+ <table>
64
+ <tr>
65
+ <td><img src="<?php echo WooCommerce_PDF_Invoices::$plugin_url . 'images/cloud-print.png'; ?>" class="cloud-logo"></td>
66
+ <td>
67
+ <?php _e( 'Check out the WooCommerce Automatic Order Printing extension from our partners at Simba Hosting', 'wpo_wcpdf' ); ?><br/>
68
+ <a href="https://www.simbahosting.co.uk/s3/product/woocommerce-automatic-order-printing/?affiliates=2" target="_blank"><?php _e("WooCommerce Automatic Order Printing", 'wpo_wcpdf'); ?></a>
69
+ </td>
70
+ </tr>
71
+ </table>
72
+ </div>
73
+ </li>
74
+ <?php } ?>
75
+
76
+ <?php
77
+ if (!class_exists('WooCommerce_PDF_IPS_Templates')) {
78
+ $template_link = '<a href="https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/" target="_blank">wpovernight.com</a>';
79
+ $email_link = '<a href="mailto:support@wpovernight.com">support@wpovernight.com</a>'
80
+ ?>
81
+ <li>
82
+ <?php _e('Advanced, customizable templates', 'wpo_wcpdf')?>
83
+ <div class="more" style="display:none;">
84
+ <ul>
85
+ <li><?php _e( 'Completely customize the invoice contents (prices, taxes, thumbnails) to your needs with a drag & drop customizer', 'wpo_wcpdf' ); ?></li>
86
+ <li><?php _e( 'Two extra stylish premade templates (Modern & Business)', 'wpo_wcpdf' ); ?></li>
87
+ <li><?php printf( __("Check out the Premium PDF Invoice & Packing Slips templates at %s.", 'wpo_wcpdf'), $template_link );?></li>
88
+ <li><?php printf( __("For custom templates, contact us at %s.", 'wpo_wcpdf'), $email_link );?></li>
89
+ </ul>
90
+ </div>
91
+ </li>
92
+ <?php } ?>
93
+ </ul>
94
+ <?php
95
+ // link to hide message when one of the premium extensions is installed
96
+ if ( class_exists('WooCommerce_PDF_IPS_Pro') || class_exists('WooCommerce_PDF_IPS_Dropbox') || class_exists('WooCommerce_PDF_IPS_Templates') || class_exists('WooCommerce_Ext_PrintOrders') ) {
97
+ printf('<a href="%s" style="display:inline-block; margin-top: 10px;">%s</a>', add_query_arg( 'wpo_wcpdf_hide_extensions_ad', 'true' ), __( 'Hide this message', 'wpo_wcpdf' ) );
98
+ }
99
+ ?>
100
  </div>
languages/wpo_wcpdf-de_DE_formal.mo ADDED
Binary file
languages/wpo_wcpdf-de_DE_formal.po ADDED
@@ -0,0 +1,692 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: WooCommerce PDF Invoices & Packing Slips\n"
4
+ "POT-Creation-Date: 2015-04-29 08:59+0100\n"
5
+ "PO-Revision-Date: 2015-04-29 09:02+0100\n"
6
+ "Last-Translator: Jens Nachtigall <mail@nachtigall.io>\n"
7
+ "Language-Team: PROnatur24 <info@pronatur24.eu>\n"
8
+ "Language: de_DE\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.7.5\n"
13
+ "X-Poedit-Basepath: ../\n"
14
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "X-Poedit-KeywordsList: __;_e;_x;_n:1,2\n"
17
+ "X-Poedit-SearchPath-0: .\n"
18
+
19
+ #: includes/class-wcpdf-export.php:338 includes/class-wcpdf-export.php:348
20
+ #: includes/class-wcpdf-export.php:359 includes/class-wcpdf-export.php:367
21
+ msgid "You do not have sufficient permissions to access this page."
22
+ msgstr "Du hast keine Berechtigung diese Seite anzuzeigen."
23
+
24
+ #: includes/class-wcpdf-export.php:343
25
+ msgid "Some of the export parameters are missing."
26
+ msgstr ""
27
+
28
+ # This is a filename (prefix). do not use spaces or special characters!
29
+ #: includes/class-wcpdf-export.php:424
30
+ msgid "invoice"
31
+ msgid_plural "invoices"
32
+ msgstr[0] "Rechnung"
33
+ msgstr[1] "Rechnungen"
34
+
35
+ # This is a filename (prefix). do not use spaces or special characters!
36
+ #: includes/class-wcpdf-export.php:428
37
+ msgid "packing-slip"
38
+ msgid_plural "packing-slips"
39
+ msgstr[0] "Lieferschein"
40
+ msgstr[1] "Lieferscheine"
41
+
42
+ #: includes/class-wcpdf-settings.php:38 includes/class-wcpdf-settings.php:39
43
+ #: includes/class-wcpdf-writepanels.php:32
44
+ msgid "PDF Invoices"
45
+ msgstr "PDF Rechnungen"
46
+
47
+ #: includes/class-wcpdf-settings.php:80
48
+ msgid "Settings"
49
+ msgstr "Einstellungen"
50
+
51
+ #: includes/class-wcpdf-settings.php:102
52
+ msgid "General"
53
+ msgstr "Allgemein"
54
+
55
+ #: includes/class-wcpdf-settings.php:103
56
+ msgid "Template"
57
+ msgstr "Vorlage"
58
+
59
+ #: includes/class-wcpdf-settings.php:108
60
+ msgid "Status"
61
+ msgstr "Status"
62
+
63
+ #: includes/class-wcpdf-settings.php:120
64
+ msgid "WooCommerce PDF Invoices"
65
+ msgstr "WooCommerce PDF Rechnungen"
66
+
67
+ #: includes/class-wcpdf-settings.php:189
68
+ msgid "General settings"
69
+ msgstr "Allgemeine Einstellungen"
70
+
71
+ #: includes/class-wcpdf-settings.php:196
72
+ msgid "How do you want to view the PDF?"
73
+ msgstr "Wie soll das PDF angezeigt werden?"
74
+
75
+ #: includes/class-wcpdf-settings.php:204
76
+ msgid "Download the PDF"
77
+ msgstr "PDF runterladen"
78
+
79
+ #: includes/class-wcpdf-settings.php:205
80
+ msgid "Open the PDF in a new browser tab/window"
81
+ msgstr "PDF in einem neuen Browser Tab/Fenster öffnen"
82
+
83
+ #: includes/class-wcpdf-settings.php:214
84
+ msgid "Admin New Order email"
85
+ msgstr "Admin Neue Bestellung E-Mail"
86
+
87
+ #: includes/class-wcpdf-settings.php:215
88
+ msgid "Customer Processing Order email"
89
+ msgstr "Kunde In Bearbeitung E-Mail"
90
+
91
+ #: includes/class-wcpdf-settings.php:216
92
+ msgid "Customer Completed Order email"
93
+ msgstr "Kunde Bestellung abgeschlossen E-Mail"
94
+
95
+ #: includes/class-wcpdf-settings.php:217
96
+ msgid "Customer Invoice email"
97
+ msgstr "Kunde Rechnung E-Mail"
98
+
99
+ #: includes/class-wcpdf-settings.php:222
100
+ msgid "Attach invoice to:"
101
+ msgstr "Rechnung anfügen zu:"
102
+
103
+ #: includes/class-wcpdf-settings.php:230
104
+ #, php-format
105
+ msgid ""
106
+ "It looks like the temp folder (<code>%s</code>) is not writable, check the "
107
+ "permissions for this folder! Without having write access to this folder, the "
108
+ "plugin will not be able to email invoices."
109
+ msgstr ""
110
+ "Das temporäre Verzeichnis (<code>%s</code>) ist nicht beschreibbar, bitte "
111
+ "überprüfe die Berechtigungen dieses Verzeichnisses. Ohne Schreibrechte "
112
+ "können keine E-Mail - Rechnungen verschickt werden."
113
+
114
+ #: includes/class-wcpdf-settings.php:236
115
+ msgid "Disable for free products"
116
+ msgstr ""
117
+
118
+ #: includes/class-wcpdf-settings.php:243
119
+ msgid ""
120
+ "Disable automatic creation/attachment of invoices when only free products "
121
+ "are ordered"
122
+ msgstr ""
123
+
124
+ #: includes/class-wcpdf-settings.php:250
125
+ msgid "Interface"
126
+ msgstr ""
127
+
128
+ #: includes/class-wcpdf-settings.php:298
129
+ msgid "Allow My Account invoice download"
130
+ msgstr ""
131
+
132
+ #: includes/class-wcpdf-settings.php:306
133
+ msgid "Only when an invoice is already created/emailed"
134
+ msgstr ""
135
+
136
+ #: includes/class-wcpdf-settings.php:307
137
+ msgid "Only for specific order statuses (define below)"
138
+ msgstr ""
139
+
140
+ #: includes/class-wcpdf-settings.php:308
141
+ msgid "Always"
142
+ msgstr ""
143
+
144
+ #: includes/class-wcpdf-settings.php:323
145
+ msgid "Enable invoice number column in the orders list"
146
+ msgstr "Aktivierung Spalte Rechnungsnummer in Bestellübersicht"
147
+
148
+ #: includes/class-wcpdf-settings.php:361
149
+ msgid "PDF Template settings"
150
+ msgstr "PDF Vorlageneinstellungen"
151
+
152
+ #: includes/class-wcpdf-settings.php:373
153
+ msgid "Choose a template"
154
+ msgstr "Wähle ein Template"
155
+
156
+ #: includes/class-wcpdf-settings.php:381
157
+ #, php-format
158
+ msgid ""
159
+ "Want to use your own template? Copy all the files from <code>%s</code> to "
160
+ "your (child) theme in <code>%s</code> to customize them"
161
+ msgstr ""
162
+ "Wenn du eigene Vorlagen verwenden willst, dann kopiere alle Dateien von "
163
+ "<code>%s</code> nach <code>%s</code> und passe sie dort an."
164
+
165
+ #: includes/class-wcpdf-settings.php:387
166
+ msgid "Paper size"
167
+ msgstr "Papierformat"
168
+
169
+ #: includes/class-wcpdf-settings.php:395
170
+ msgid "A4"
171
+ msgstr "A4"
172
+
173
+ #: includes/class-wcpdf-settings.php:396
174
+ msgid "Letter"
175
+ msgstr "Letter"
176
+
177
+ #: includes/class-wcpdf-settings.php:403
178
+ msgid "Shop header/logo"
179
+ msgstr "Briefkopf-Logo"
180
+
181
+ #: includes/class-wcpdf-settings.php:410
182
+ msgid "Select or upload your invoice header/logo"
183
+ msgstr "Auswählen oder hochladen des Logos"
184
+
185
+ #: includes/class-wcpdf-settings.php:411
186
+ msgid "Set image"
187
+ msgstr "Logo festlegen"
188
+
189
+ #: includes/class-wcpdf-settings.php:412
190
+ msgid "Remove image"
191
+ msgstr "Logo entfernen"
192
+
193
+ #: includes/class-wcpdf-settings.php:419
194
+ msgid "Shop Name"
195
+ msgstr "Name des Shops"
196
+
197
+ #: includes/class-wcpdf-settings.php:432
198
+ msgid "Shop Address"
199
+ msgstr "Adresse des Shops"
200
+
201
+ #: includes/class-wcpdf-settings.php:447
202
+ msgid "Footer: terms & conditions, policies, etc."
203
+ msgstr "Fußzeile: allgemeine Bestimmungen, etc."
204
+
205
+ #: includes/class-wcpdf-settings.php:463 templates/pdf/Simple/invoice.php:9
206
+ #: templates/pdf/Simple/invoice.php:21
207
+ #: woocommerce-pdf-invoices-packingslips.php:220
208
+ msgid "Invoice"
209
+ msgstr "Rechnung"
210
+
211
+ #: includes/class-wcpdf-settings.php:470
212
+ msgid "Display shipping address"
213
+ msgstr ""
214
+
215
+ #: includes/class-wcpdf-settings.php:477
216
+ msgid ""
217
+ "Display shipping address on invoice (in addition to the default billing "
218
+ "address) if different from billing address"
219
+ msgstr ""
220
+
221
+ #: includes/class-wcpdf-settings.php:483 includes/class-wcpdf-settings.php:598
222
+ msgid "Display email address"
223
+ msgstr ""
224
+
225
+ #: includes/class-wcpdf-settings.php:495 includes/class-wcpdf-settings.php:610
226
+ msgid "Display phone number"
227
+ msgstr ""
228
+
229
+ #: includes/class-wcpdf-settings.php:507
230
+ msgid "Display invoice date"
231
+ msgstr "Rechnungsdatum anzeigen"
232
+
233
+ #: includes/class-wcpdf-settings.php:520
234
+ msgid "Display built-in sequential invoice number"
235
+ msgstr "Anzeige integrierte fortlaufende Rechnungsnummer"
236
+
237
+ #: includes/class-wcpdf-settings.php:533
238
+ msgid "Next invoice number (without prefix/suffix etc.)"
239
+ msgstr "Nächste Rechnungsnummer (ohne Präfix/Suffix usw.)"
240
+
241
+ #: includes/class-wcpdf-settings.php:541
242
+ msgid ""
243
+ "This is the number that will be used on the next invoice that is created. By "
244
+ "default, numbering starts from the WooCommerce Order Number of the first "
245
+ "invoice that is created and increases for every new invoice. Note that if "
246
+ "you override this and set it lower than the highest (PDF) invoice number, "
247
+ "this could create double invoice numbers!"
248
+ msgstr ""
249
+ "Dies ist die Nummer welche für die nächste Rechnung verwendet wird. "
250
+ "Vordefiniert startet die Rechnungsnummerierung mit der WooCommerce "
251
+ "Bestellnummer auf der ersten generierten Rechnung und erhöht mit jeder neuen "
252
+ "Rechnung. Beachte bitte das die Überschreibung der höchsten (PDF) "
253
+ "Rechnungsnummer mit einer kleineren Nummer zu doppelten Rechnungsnummern "
254
+ "führen kann."
255
+
256
+ #: includes/class-wcpdf-settings.php:547
257
+ msgid "Invoice number format"
258
+ msgstr "Rechnungsnummer"
259
+
260
+ #: includes/class-wcpdf-settings.php:556
261
+ msgid "Prefix"
262
+ msgstr "Präfix"
263
+
264
+ #: includes/class-wcpdf-settings.php:558
265
+ msgid ""
266
+ "to use the order year and/or month, use [order_year] or [order_month] "
267
+ "respectively"
268
+ msgstr ""
269
+ "um das Bestelljahr und/oder -monat zu nutzen, verwende [order_year] oder "
270
+ "[order_month]"
271
+
272
+ #: includes/class-wcpdf-settings.php:561
273
+ msgid "Suffix"
274
+ msgstr "Suffix"
275
+
276
+ #: includes/class-wcpdf-settings.php:566
277
+ msgid "Padding"
278
+ msgstr "Abstand"
279
+
280
+ #: includes/class-wcpdf-settings.php:568
281
+ msgid "enter the number of digits here - enter \"6\" to display 42 as 000042"
282
+ msgstr ""
283
+ "Anzahl der Zeichen hier eingeben - \"6\" eingeben um 42 als 000042 "
284
+ "darzustellen"
285
+
286
+ #: includes/class-wcpdf-settings.php:571
287
+ msgid ""
288
+ "note: if you have already created a custom invoice number format with a "
289
+ "filter, the above settings will be ignored"
290
+ msgstr ""
291
+ "beachte: solltest du schon mit einem Filter ein eigenes Format der "
292
+ "Rechnungsnummer erstellt haben, werden obige Einstellungen ignoriert"
293
+
294
+ #: includes/class-wcpdf-settings.php:578
295
+ #: templates/pdf/Simple/packing-slip.php:9
296
+ #: templates/pdf/Simple/packing-slip.php:21
297
+ #: woocommerce-pdf-invoices-packingslips.php:223
298
+ msgid "Packing Slip"
299
+ msgstr "Lieferschein"
300
+
301
+ #: includes/class-wcpdf-settings.php:585
302
+ msgid "Display billing address"
303
+ msgstr ""
304
+
305
+ #: includes/class-wcpdf-settings.php:592
306
+ msgid ""
307
+ "Display billing address on packing slip (in addition to the default shipping "
308
+ "address) if different from shipping address"
309
+ msgstr ""
310
+
311
+ #: includes/class-wcpdf-settings.php:623
312
+ msgid "Extra template fields"
313
+ msgstr "Zusätzliche Vorlagenfelder"
314
+
315
+ #: includes/class-wcpdf-settings.php:630
316
+ msgid "Extra field 1"
317
+ msgstr "Zusatzfeld 1"
318
+
319
+ #: includes/class-wcpdf-settings.php:639
320
+ msgid "This is footer column 1 in the <i>Modern (Premium)</i> template"
321
+ msgstr ""
322
+ "Das ist die Spalte 1 in der Fußzeile der <i>Modern (Premium)</i> Vorlage"
323
+
324
+ #: includes/class-wcpdf-settings.php:645
325
+ msgid "Extra field 2"
326
+ msgstr "Zusatzfeld 2"
327
+
328
+ #: includes/class-wcpdf-settings.php:654
329
+ msgid "This is footer column 2 in the <i>Modern (Premium)</i> template"
330
+ msgstr ""
331
+ "Das ist die Spalte 2 in der Fußzeile der <i>Modern (Premium)</i> Vorlage"
332
+
333
+ #: includes/class-wcpdf-settings.php:660
334
+ msgid "Extra field 3"
335
+ msgstr "Zusatzfeld 3"
336
+
337
+ #: includes/class-wcpdf-settings.php:669
338
+ msgid "This is footer column 3 in the <i>Modern (Premium)</i> template"
339
+ msgstr ""
340
+ "Das ist die Spalte 3 in der Fußzeile der <i>Modern (Premium)</i> Vorlage"
341
+
342
+ #: includes/class-wcpdf-settings.php:711
343
+ msgid "Debug settings"
344
+ msgstr ""
345
+
346
+ #: includes/class-wcpdf-settings.php:718
347
+ msgid "Enable debug output"
348
+ msgstr ""
349
+
350
+ #: includes/class-wcpdf-settings.php:725
351
+ msgid ""
352
+ "Enable this option to output plugin errors if you're getting a blank page or "
353
+ "other PDF generation issues"
354
+ msgstr ""
355
+
356
+ #: includes/class-wcpdf-settings.php:731
357
+ msgid "Output to HTML"
358
+ msgstr ""
359
+
360
+ #: includes/class-wcpdf-settings.php:738
361
+ msgid ""
362
+ "Send the template output as HTML to the browser instead of creating a PDF."
363
+ msgstr ""
364
+
365
+ #: includes/class-wcpdf-settings.php:744
366
+ msgid "Use old tmp folder"
367
+ msgstr ""
368
+
369
+ #: includes/class-wcpdf-settings.php:751
370
+ msgid ""
371
+ "Before version 1.5 of PDF Invoices, temporary files were stored in the "
372
+ "plugin folder. This setting is only intended for backwards compatibility, "
373
+ "not recommended on new installs!"
374
+ msgstr ""
375
+
376
+ #: includes/class-wcpdf-settings.php:1091
377
+ msgid "Image resolution"
378
+ msgstr "Bildauflösung"
379
+
380
+ #: includes/class-wcpdf-settings.php:1207
381
+ msgid ""
382
+ "<b>Warning!</b> The settings below are meant for debugging/development only. "
383
+ "Do not use them on a live website!"
384
+ msgstr ""
385
+
386
+ #: includes/class-wcpdf-settings.php:1216
387
+ msgid ""
388
+ "These are used for the (optional) footer columns in the <em>Modern "
389
+ "(Premium)</em> template, but can also be used for other elements in your "
390
+ "custom template"
391
+ msgstr ""
392
+ "Diese Felder werden in den Spalten der (optionalen) Fußzeile der <em>Modern "
393
+ "(Premium)</em> Vorlage verwendet, können aber auch für andere Elemente in "
394
+ "deiner angepassten Vorlage verwendet werden."
395
+
396
+ #: includes/class-wcpdf-writepanels.php:33
397
+ msgid "PDF Packing Slips"
398
+ msgstr "PDF Lieferscheine"
399
+
400
+ #: includes/class-wcpdf-writepanels.php:107
401
+ #: includes/class-wcpdf-writepanels.php:216
402
+ msgid "PDF Invoice"
403
+ msgstr "PDF Rechnung"
404
+
405
+ #: includes/class-wcpdf-writepanels.php:112
406
+ #: includes/class-wcpdf-writepanels.php:221
407
+ msgid "PDF Packing Slip"
408
+ msgstr "PDF Lieferschein"
409
+
410
+ #: includes/class-wcpdf-writepanels.php:139
411
+ msgid "Invoice Number"
412
+ msgstr "Rechnungsnummer"
413
+
414
+ #: includes/class-wcpdf-writepanels.php:192
415
+ msgid "Download invoice (PDF)"
416
+ msgstr "Rechnung runterladen (PDF)"
417
+
418
+ #: includes/class-wcpdf-writepanels.php:203
419
+ msgid "Create PDF"
420
+ msgstr "PDF erstellen"
421
+
422
+ #: includes/class-wcpdf-writepanels.php:264
423
+ msgid "PDF Invoice Number (unformatted!)"
424
+ msgstr "PDF Rechnungsnummer (unformatiert)"
425
+
426
+ #: includes/class-wcpdf-writepanels.php:267
427
+ #: templates/pdf/Simple/invoice.php:55
428
+ msgid "Invoice Date:"
429
+ msgstr "Rechnungsdatum:"
430
+
431
+ #: includes/class-wcpdf-writepanels.php:268
432
+ msgid "h"
433
+ msgstr "Std"
434
+
435
+ #: includes/class-wcpdf-writepanels.php:268
436
+ msgid "m"
437
+ msgstr "Min"
438
+
439
+ #: includes/wcpdf-extensions.php:15
440
+ msgid "Check out these premium extensions!"
441
+ msgstr "Premium Erweiterungen schon gesehen?"
442
+
443
+ #: includes/wcpdf-extensions.php:16
444
+ msgid "click items to read more"
445
+ msgstr "klicke Elemente um weiterzulesen"
446
+
447
+ #: includes/wcpdf-extensions.php:23
448
+ msgid "Go Pro: Proforma invoices, credit notes (=refunds) & more!"
449
+ msgstr "Upgrade auf Pro: Proforma Rechnung, Gutschrift & mehr!"
450
+
451
+ #: includes/wcpdf-extensions.php:25
452
+ msgid ""
453
+ "Supercharge WooCommerce PDF Invoices & Packing Slips with the following "
454
+ "features:"
455
+ msgstr ""
456
+ "Verbessere WooCommerce PDF Invoices & Packing Slips mit diesen Funktionen:"
457
+
458
+ #: includes/wcpdf-extensions.php:27
459
+ msgid "Email/print/download <b>PDF Credit Notes & Proforma invoices</b>"
460
+ msgstr "E-Mail/Druck/Download <b>PDF Gutschrift & Proforma Rechnung</b>"
461
+
462
+ #: includes/wcpdf-extensions.php:28
463
+ msgid ""
464
+ "Send out a separate <b>notification email</b> with (or without) PDF invoices/"
465
+ "packing slips, for example to a drop-shipper or a supplier."
466
+ msgstr ""
467
+
468
+ #: includes/wcpdf-extensions.php:29
469
+ msgid ""
470
+ "Attach <b>up to 3 static files</b> (for example a terms & conditions "
471
+ "document) to the WooCommerce emails of your choice."
472
+ msgstr ""
473
+
474
+ #: includes/wcpdf-extensions.php:30
475
+ msgid ""
476
+ "Use <b>separate numbering systems</b> and/or format for proforma invoices "
477
+ "and credit notes or utilize the main invoice numbering system"
478
+ msgstr ""
479
+ "Anwendung <b>separates Nummerierungssystem</b> und/oder Format für Proforma "
480
+ "Rechnungen und Gutschriften oder Änderung am Hauptsystem der "
481
+ "Rechnungsnummerierung"
482
+
483
+ #: includes/wcpdf-extensions.php:31
484
+ msgid ""
485
+ "<b>Customize</b> the <b>shipping & billing address</b> format to include "
486
+ "additional custom fields, font sizes etc. without the need to create a "
487
+ "custom template."
488
+ msgstr ""
489
+ "<b>Anpassung</b> vom <b>Liefer- & Rechnugnsadresse</b> Format um zusätzliche "
490
+ "freie Felder, Schriftgrößen, usw. einzufügen ohne ein individuellen Template "
491
+ "zu erstellen."
492
+
493
+ #: includes/wcpdf-extensions.php:32
494
+ msgid "Use the plugin in multilingual <b>WPML</b> setups"
495
+ msgstr "Nutzung vom Plugin für Multisprachen <b>WPML</b> Einrichtungen"
496
+
497
+ #: includes/wcpdf-extensions.php:34
498
+ msgid "Get WooCommerce PDF Invoices & Packing Slips Professional!"
499
+ msgstr "Hole WooCommerce PDF Invoices & Packing Slips Professional!"
500
+
501
+ #: includes/wcpdf-extensions.php:42
502
+ msgid "Upload all invoices automatically to your dropbox"
503
+ msgstr "Alle Rechnungen automatisch auf deine Dropbox hochladen"
504
+
505
+ #: includes/wcpdf-extensions.php:48
506
+ msgid ""
507
+ "This extension conveniently uploads all the invoices (and other pdf "
508
+ "documents from the professional extension) that are emailed to your "
509
+ "customers to Dropbox. The best way to keep your invoice administration up to "
510
+ "date!"
511
+ msgstr ""
512
+ "Diese Erweiterung lädt alle Rechnungen (und zusätzlich aktivieren PDF "
513
+ "Dokumente) die dem Kunden gemailt werden zur Dropbox. Die beste Weise um die "
514
+ "Rechnungsadministration aktuell zu halten!"
515
+
516
+ #: includes/wcpdf-extensions.php:49
517
+ msgid "Get WooCommerce PDF Invoices & Packing Slips to dropbox!"
518
+ msgstr "Hole WooCommerce PDF Invoices & Packing Slips to dropbox!"
519
+
520
+ #: includes/wcpdf-extensions.php:61
521
+ msgid ""
522
+ "Automatically send new orders or packing slips to your printer, as soon as "
523
+ "the customer orders!"
524
+ msgstr ""
525
+ "Schicke neue Bestellungen oder Lieferscheine automatisch an deinen Drucker, "
526
+ "sobald ein Kunde bestellt."
527
+
528
+ #: includes/wcpdf-extensions.php:67
529
+ msgid ""
530
+ "Check out the WooCommerce Automatic Order Printing extension from our "
531
+ "partners at Simba Hosting"
532
+ msgstr ""
533
+ "Probiere die Erweiterung „WooCommerce Automatic Order Printing“ unserem "
534
+ "Partner Simba Hosting "
535
+
536
+ #: includes/wcpdf-extensions.php:68
537
+ msgid "WooCommerce Automatic Order Printing"
538
+ msgstr "WooCommerce Automatic Order Printing"
539
+
540
+ #: includes/wcpdf-extensions.php:82
541
+ msgid "More advanced templates"
542
+ msgstr "Weiter entwickelte Voralgen"
543
+
544
+ #: includes/wcpdf-extensions.php:85
545
+ msgid "Stylish modern invoices & packing slips with product thumbnails!"
546
+ msgstr ""
547
+ "Stylisch moderne Rechnungen & Lieferscheine mit Miniaturbildern vom Produkt!"
548
+
549
+ #: includes/wcpdf-extensions.php:86
550
+ msgid "More tax details on the invoices!"
551
+ msgstr "Zusätzliche Steuerdetails auf der Rechnung!"
552
+
553
+ #: includes/wcpdf-extensions.php:87
554
+ #, php-format
555
+ msgid "Check out the Premium PDF Invoice & Packing Slips templates at %s."
556
+ msgstr "Schau dir die Premium PDF Invoice & Packing Slips Vorlagen an auf %s."
557
+
558
+ #: includes/wcpdf-extensions.php:88
559
+ #, php-format
560
+ msgid "For custom templates, contact us at %s."
561
+ msgstr "Für individuelle Vorlagen kontaktiert uns auf %s."
562
+
563
+ #: templates/pdf/Simple/invoice.php:29
564
+ #: templates/pdf/Simple/packing-slip.php:40
565
+ msgid "Billing Address:"
566
+ msgstr "Rechnungsadresse:"
567
+
568
+ #: templates/pdf/Simple/invoice.php:40
569
+ msgid "Ship To:"
570
+ msgstr "Versand nach:"
571
+
572
+ #: templates/pdf/Simple/invoice.php:49
573
+ msgid "Invoice Number:"
574
+ msgstr "Rechnungsnummer:"
575
+
576
+ #: templates/pdf/Simple/invoice.php:60
577
+ #: templates/pdf/Simple/packing-slip.php:48
578
+ msgid "Order Number:"
579
+ msgstr "Bestellnummer:"
580
+
581
+ #: templates/pdf/Simple/invoice.php:64
582
+ #: templates/pdf/Simple/packing-slip.php:52
583
+ msgid "Order Date:"
584
+ msgstr "Bestelldatum:"
585
+
586
+ #: templates/pdf/Simple/invoice.php:68
587
+ msgid "Payment Method:"
588
+ msgstr "Zahlungsart:"
589
+
590
+ #: templates/pdf/Simple/invoice.php:82
591
+ #: templates/pdf/Simple/packing-slip.php:70
592
+ msgid "Product"
593
+ msgstr "Produkt"
594
+
595
+ #: templates/pdf/Simple/invoice.php:83
596
+ #: templates/pdf/Simple/packing-slip.php:71
597
+ msgid "Quantity"
598
+ msgstr "Anzahl"
599
+
600
+ #: templates/pdf/Simple/invoice.php:84
601
+ msgid "Price"
602
+ msgstr "Preis"
603
+
604
+ #: templates/pdf/Simple/invoice.php:91
605
+ #: templates/pdf/Simple/packing-slip.php:78
606
+ msgid "Description"
607
+ msgstr "Beschreibung"
608
+
609
+ #: templates/pdf/Simple/invoice.php:96
610
+ #: templates/pdf/Simple/packing-slip.php:83
611
+ msgid "SKU"
612
+ msgstr "Art.-Nr."
613
+
614
+ #: templates/pdf/Simple/invoice.php:97
615
+ #: templates/pdf/Simple/packing-slip.php:84
616
+ msgid "SKU:"
617
+ msgstr "Art.-Nr.:"
618
+
619
+ #: templates/pdf/Simple/invoice.php:98
620
+ #: templates/pdf/Simple/packing-slip.php:85
621
+ msgid "Weight:"
622
+ msgstr "Gewicht:"
623
+
624
+ #: templates/pdf/Simple/invoice.php:112
625
+ #: templates/pdf/Simple/packing-slip.php:99
626
+ msgid "Customer Notes"
627
+ msgstr "Anmerkungen"
628
+
629
+ #: templates/pdf/Simple/packing-slip.php:29
630
+ msgid "Shipping Address:"
631
+ msgstr "Lieferadresse:"
632
+
633
+ #: templates/pdf/Simple/packing-slip.php:56
634
+ msgid "Shipping Method:"
635
+ msgstr "Versandart:"
636
+
637
+ #: woocommerce-pdf-invoices-packingslips.php:123
638
+ #, php-format
639
+ msgid ""
640
+ "WooCommerce PDF Invoices & Packing Slips requires %sWooCommerce%s to be "
641
+ "installed & activated!"
642
+ msgstr ""
643
+ "WooCommerce PDF Invoices & Packing Slips benötigt %sWooCommerce%s "
644
+ "installiert und aktiviert!"
645
+
646
+ #: woocommerce-pdf-invoices-packingslips.php:330
647
+ #: woocommerce-pdf-invoices-packingslips.php:391
648
+ msgid "N/A"
649
+ msgstr "nicht verfügbar"
650
+
651
+ #: woocommerce-pdf-invoices-packingslips.php:480
652
+ msgid "Payment method"
653
+ msgstr "Zahlungsart"
654
+
655
+ #: woocommerce-pdf-invoices-packingslips.php:491
656
+ msgid "Shipping method"
657
+ msgstr "Versandart"
658
+
659
+ #: woocommerce-pdf-invoices-packingslips.php:644
660
+ msgid "Subtotal"
661
+ msgstr "Zwischensumme"
662
+
663
+ #: woocommerce-pdf-invoices-packingslips.php:666
664
+ msgid "Shipping"
665
+ msgstr "Versand"
666
+
667
+ #: woocommerce-pdf-invoices-packingslips.php:719
668
+ msgid "Discount"
669
+ msgstr "Rabatt"
670
+
671
+ #: woocommerce-pdf-invoices-packingslips.php:759
672
+ msgid "VAT"
673
+ msgstr "MwSt."
674
+
675
+ #: woocommerce-pdf-invoices-packingslips.php:760
676
+ msgid "Tax rate"
677
+ msgstr "MwSt-Satz"
678
+
679
+ #: woocommerce-pdf-invoices-packingslips.php:797
680
+ msgid "Total ex. VAT"
681
+ msgstr "Gesamtsumme ohne MwSt."
682
+
683
+ #: woocommerce-pdf-invoices-packingslips.php:800
684
+ msgid "Total"
685
+ msgstr "Gesamtsumme"
686
+
687
+ #~ msgid ""
688
+ #~ "Attach a <b>static file</b> (for example a terms & conditions document) "
689
+ #~ "to the WooCommerce emails of your choice."
690
+ #~ msgstr ""
691
+ #~ "Hinzufügen einer beliebigen <b>Datei </b> (beispielweise AGB, "
692
+ #~ "Widerrufsbelehrung) zum WooCommerce E-Mail"
lib/dompdf/lib/fonts/{01847c3483fce00998f5049154250e7f.ttf → cd6cad1255d2179b7fe44d496b229dae.ttf} RENAMED
Binary file
lib/dompdf/lib/fonts/{01847c3483fce00998f5049154250e7f.ufm → cd6cad1255d2179b7fe44d496b229dae.ufm} RENAMED
@@ -20,12 +20,12 @@ Weight Bold
20
  ItalicAngle 0
21
  IsFixedPitch false
22
  UnderlineThickness 50
23
- UnderlinePosition -200
24
  FontHeightOffset 0
25
  Ascender 977
26
  Descender -293
27
  FontBBox -20 -293 1047 977
28
- StartCharMetrics 48
29
  U 32 ; WX 391 ; N space ; G 3
30
  U 36 ; WX 514 ; N uni0024 ; G 4
31
  U 160 ; WX 391 ; N uni00A0 ; G 5
@@ -65,11 +65,14 @@ U 8370 ; WX 650 ; N uni20B2 ; G 38
65
  U 8371 ; WX 760 ; N uni20B3 ; G 39
66
  U 8372 ; WX 643 ; N uni20B4 ; G 40
67
  U 8373 ; WX 650 ; N uni20B5 ; G 41
68
- U 8499 ; WX 824 ; N uni2133 ; G 42
69
- U 20803 ; WX 1000 ; N uni5143 ; G 43
70
- U 20870 ; WX 1000 ; N uni5186 ; G 44
71
- U 22278 ; WX 1000 ; N uni5706 ; G 45
72
- U 22291 ; WX 1000 ; N uni5713 ; G 46
73
- U 65020 ; WX 1086 ; N uniFDFC ; G 47
 
 
 
74
  EndCharMetrics
75
  EndFontMetrics
20
  ItalicAngle 0
21
  IsFixedPitch false
22
  UnderlineThickness 50
23
+ UnderlinePosition -250
24
  FontHeightOffset 0
25
  Ascender 977
26
  Descender -293
27
  FontBBox -20 -293 1047 977
28
+ StartCharMetrics 51
29
  U 32 ; WX 391 ; N space ; G 3
30
  U 36 ; WX 514 ; N uni0024 ; G 4
31
  U 160 ; WX 391 ; N uni00A0 ; G 5
65
  U 8371 ; WX 760 ; N uni20B3 ; G 39
66
  U 8372 ; WX 643 ; N uni20B4 ; G 40
67
  U 8373 ; WX 650 ; N uni20B5 ; G 41
68
+ U 8377 ; WX 636 ; N uni20B9 ; G 42
69
+ U 8378 ; WX 636 ; N uni20BA ; G 43
70
+ U 8381 ; WX 636 ; N uni20BD ; G 44
71
+ U 8499 ; WX 824 ; N uni2133 ; G 45
72
+ U 20803 ; WX 1000 ; N uni5143 ; G 46
73
+ U 20870 ; WX 1000 ; N uni5186 ; G 47
74
+ U 22278 ; WX 1000 ; N uni5706 ; G 48
75
+ U 22291 ; WX 1000 ; N uni5713 ; G 49
76
+ U 65020 ; WX 1086 ; N uniFDFC ; G 50
77
  EndCharMetrics
78
  EndFontMetrics
lib/dompdf/lib/fonts/dompdf_font_family_cache.php CHANGED
@@ -87,9 +87,9 @@
87
  ),
88
  'currencies' =>
89
  array (
90
- 'normal' => DOMPDF_FONT_DIR . '01847c3483fce00998f5049154250e7f',
91
- 'bold' => DOMPDF_FONT_DIR . '01847c3483fce00998f5049154250e7f',
92
- 'italic' => DOMPDF_FONT_DIR . '01847c3483fce00998f5049154250e7f',
93
- 'bold_italic' => DOMPDF_FONT_DIR . '01847c3483fce00998f5049154250e7f',
94
  ),
95
  ) ?>
87
  ),
88
  'currencies' =>
89
  array (
90
+ 'normal' => DOMPDF_FONT_DIR . 'cd6cad1255d2179b7fe44d496b229dae',
91
+ 'bold' => DOMPDF_FONT_DIR . 'cd6cad1255d2179b7fe44d496b229dae',
92
+ 'italic' => DOMPDF_FONT_DIR . 'cd6cad1255d2179b7fe44d496b229dae',
93
+ 'bold_italic' => DOMPDF_FONT_DIR . 'cd6cad1255d2179b7fe44d496b229dae',
94
  ),
95
  ) ?>
readme.txt CHANGED
@@ -1,610 +1,614 @@
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.5
6
- Stable tag: 1.5.31
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.31 =
239
- * Feature: [invoice_day] or [order_day] in invoice number format
240
- * Fix: Link to hide all ads when premium extensions active
241
-
242
- = 1.5.30 =
243
- * Feature: Enable currency font for extended currency support
244
- * Fix: Font sync on plugin update
245
-
246
- = 1.5.29 =
247
- * Translations: Added Croation (Thanks Neven/Spine ICT!), updated French (Thanks Sabra!)
248
- * Tweak: filter shop address before checking if it's empty
249
- * Dev: added $order to `wpo_wcpdf_template_file` filter
250
-
251
- = 1.5.28 =
252
- * 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.
253
- * Fix: Bulk actions plugin conflicts
254
- * Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
255
-
256
- = 1.5.27 =
257
- * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
258
- * Feature: WooCommerce Order Status & Actions Manager emails compatibility
259
- * Feature: Add invoice number to WC REST API
260
- * Fix: Allow positive 'discounts' (price corrections)
261
- * Fix: Discounts rounding
262
- * Translations: Updated Finnish & Portugese & POT
263
-
264
- = 1.5.26 =
265
- * Feature: Automatically list all emails registered in WooCommerce
266
- * Feature: Reset invoice number yearly
267
- * Feature: WooCommerce Chained Products compatibility
268
- * Feature: WooCommerce Product Bundles visibility settings taken into account in invoice
269
- * Fix: Disable PDF creation from trashed order_ids
270
- * Tweak: Alert when no orders selected for bulk export (Props to Dartui!)
271
- * Tweak: PDF invoice settings always under WooCommerce menu (also for premium users)
272
- * Tweak: extra $item_id passed in row class filter
273
- * Translations: Updated Slovenian, Spanish, Dutch & POT file
274
-
275
- = 1.5.24 =
276
- * Hotfix: Subscriptions renewal filter arguments
277
-
278
- = 1.5.23 =
279
- * Fix: WooCommerce Subscriptons 2.0 deprecation notice.
280
- * Tweak: better qTranslate-X support
281
- * Tweak: filter for user privileges check (wpo_wcpdf_check_privs)
282
- * Translations: French translations fix
283
-
284
- = 1.5.22 =
285
- * Fix: Workaround for bug in WPML (which cleared all settings)
286
- * Translation: fixed Polish translation for invoice
287
-
288
- = 1.5.21 =
289
- * Translations: Added Estionan (thanks Tanel!)
290
- * Tweak: WC2.4 compatibility
291
-
292
- = 1.5.20 =
293
- * Feature: Option to 'never' display My Account invoice link
294
- * Fix: Order total for refunds in WC2.4
295
- * Fix: notice when no custom statuses selected for My Account display
296
- * Tweak: Product bundles styles
297
-
298
- = 1.5.19 =
299
- * Fix: Invoice number search (broke other custom searches)
300
-
301
- = 1.5.18 =
302
- * Fix: wpo_wcpdf_item_row_class packing slip filter arguments
303
-
304
- = 1.5.17 =
305
- * Feature: WooCommerce Product Bundles compatibility styles
306
- * Tweak: wpo_wcpdf_item_row_class as filter instead of action
307
-
308
- = 1.5.16 =
309
- * Feature: Search orders by invoice number (note: search on formatted invoice number only works for new orders)
310
- * Feature: Formatted invoice number stored in order
311
- * Tweak: Function parameters added to some of the filters
312
- * Tweak: WooCommerce 2.4 compatibility
313
- * Dev feature: action to add class to items table row (wpo_wcpdf_item_row_class)
314
- * Translations: Swedish updated (thanks Conney!)
315
- * Translations: Norwegian updated
316
-
317
- = 1.5.15 =
318
- * Fix: invoice number padding didn't work for values lower than 3
319
- * Tweak: WPML compatibility filter
320
- * Translations: Updated French (Thanks Nicolas!)
321
-
322
- = 1.5.14 =
323
- * Tweak: Invoice number & date edit fields moved to separate box on order edit page
324
- * Translations: Updated POT & Dutch
325
-
326
- = 1.5.13 =
327
- * Fix: Better address comparison to determine when to display alternate address
328
- * Tweak: Filter N/A addresses
329
- * Tweak: Use WooCommerce function for 2.3 discounts
330
- * Translations: Czech Updated (Thanks Ivo!)
331
- * Translations: French (minor fixes)
332
-
333
- = 1.5.12 =
334
- * Translations: added Danish, Updated POT & Italian
335
-
336
- = 1.5.11 =
337
- * Fix: Product text attributes (now checks key too)
338
- * Fix: Status page upload explanation typos
339
-
340
- = 1.5.10 =
341
- * Fix: Double check to make sure plugin doesn't attach to user emails
342
-
343
- = 1.5.9 =
344
- * Feature: Shorthand function to display product attributes: `$wpo_wcpdf->get_product_attribute( $attribute_name, $product )`
345
-
346
- = 1.5.8 =
347
- * Feature: disable invoice for free orders
348
- * Feature: action to insert data before & after item meta
349
- * Tweak: Added classes to sku & weight
350
- * Tweak: Hide payment method from totals (already shown in template)
351
- * Translations: Updated POT & Dutch
352
-
353
- = 1.5.7 =
354
- * Feature: Setting to show email address & phone number on invoice or packing slip (does not work on custom templates based on previous versions!)
355
-
356
- = 1.5.6 =
357
- * Feature: Setting to show shipping address on invoice (does not work on custom templates based on previous versions!)
358
- * Feature: My Account invoice download setting
359
- * Feature: several new template actions
360
- * Tweak: WooCommerce Bookings compatibility
361
- * Tweak: Gerenal stylesheet cleanup
362
- * Fix: temp path check/error on settings page
363
- * Fix: Document titles for credit notes and proforma (Pro)
364
- * Fix: Discount including tax
365
- * Fix: Special characters on item meta (requires WooCommerce 2.3.6)
366
- * Translations: Missing text domain on several strings
367
- * Translations: Updated POT & Dutch
368
-
369
- = 1.5.5 =
370
- * Fix: Check for incomplete line tax data (Subscriptions compatibility)
371
- * Fix: More precise template path instructions
372
- * Fix: duplicate stylesheet filter
373
- * Fix: Always prefer original order's billing address for refunds (WooCommerce EU VAT Number compatibility)
374
- * Translations: Updated German (MwSt. instead of formal Ust.)
375
- * Translations: Updated Dutch
376
-
377
- = 1.5.4 =
378
- * Tweak: include plugin version in style/script includes
379
- * Tweak: upload code cleanup
380
- * Fix: Parent invoice number (for Credit Notes in professional extension)
381
-
382
- = 1.5.3 =
383
- * Feature: add original order date value to order date filter
384
- * Feature: Work with line_tax_data when available
385
- * Feature: pass item_id to items
386
- * Tweak: later check for woocommerce active
387
- * Fix: do not try to validate empty settings (Status page settings)
388
- * Translations: Fixed Dutch typo
389
-
390
- = 1.5.2 =
391
- * Fix: fatal error when trying to activate with WooCommerce not installed yet.
392
- * Tweak: indentation fix on the Simple template
393
-
394
- = 1.5.1 =
395
- * Fix: prevent errors when upgrading
396
-
397
- = 1.5.0 =
398
- * Feature: All temporary files are now stored centrally in the WP uploads folder.
399
- * Feature: Debug settings in status panel (output errors & output to HTML)
400
- * Feature: Compatibility filter for WooCommerce Subscriptions (prevents duplicate invoice numbers)
401
- * Tweak: Pass order to totals filters
402
- * Translations: Updated POT
403
- * Translations: Updated Italian (Thanks Astrid!)
404
- * Translations: Updated Dutch
405
- * FAQ: instructions for placing a link on the thank you page
406
-
407
- = 1.4.14 =
408
- * Fix: fatal error when user registers at checkout (applies to credit notes only)
409
- * Translations: Updated German (Thanks Dietmar!)
410
- * 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.
411
-
412
- = 1.4.13 =
413
- * Feature: use separate file for all your template specific functions (template-functions.php)
414
- * Translations: Added Slovenian (thanks gregy1403!)
415
- * Translations: Updated Norwegian & Dutch.
416
- * Translations: Added Japanese - needs custom font!
417
- * FAQ: instructions on how to use custom fonts
418
-
419
- = 1.4.12 =
420
- * Fix: issues with post parent objects (WC2.1 and older)
421
-
422
- = 1.4.11 =
423
- * Small fix: bulk actions for specific i18n configurations
424
- * Tweak: total row key used as class in Simple template
425
-
426
- = 1.4.10 =
427
- * Fix: Invoice not attaching
428
- * Translations: Updated POT file
429
- * Translations: Updated Dutch, Norwegian, Polish, Brazilian Portugese, Romanian, Russian, Slovak, Spanish & Ukrainian (Many thanks to all the translators!)
430
- * 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`)
431
-
432
- = 1.4.9 =
433
- * Feature: Order number and date are now displayed by default in the Simple template (invoice number and date still optional)
434
- * Feature: Display Customer/Order notes with a simple shorthand (see FAQ)
435
- * Translations: Added Brazilian Portugese (thanks Victor Debone!)
436
- * Tweak: Fail more gracefully when there are errors during PDF generation
437
- * Tweak: added template type class to template output body
438
- * Tweak: cleaned up Simple template style.css
439
-
440
- = 1.4.8 =
441
- * Translations: Added Finnish (Thanks Sami Mäkelä/Contrast.fi!)
442
-
443
- = 1.4.7 =
444
- * Fix: check if image file exists locally, fallback to url if not (CDN compatibility)
445
- * Fix: make deleting invoice date possible
446
- * Fix: correct tmp folder check on status page
447
- * Translations: updated po/mo files
448
- * Tweak: changed settings capability requirement to `manage_woocommerce` (was: `manage_options`)
449
- * Tweak: better email attachment function
450
- * Tweak: prevent footer overlap (Simple template)
451
- * Tweak: fallback if `glob()` is not allowed on the server
452
- * Tweak: better custom template instructions (reflects path to actual (child-)theme)
453
-
454
- = 1.4.6 =
455
- * HOTFIX: WooCommerce 2.2 compatibility fix
456
- * Filter for PDF temp folder (wpo_wcpdf_tmp_path)
457
-
458
- = 1.4.5 =
459
- * Fix: Double date conversion for order date on invoice number filter (to avoid i18n date issues)
460
- * Fix: Template selector reset after update
461
- * Translations: added Norwegian (Thanks Aleksander!)
462
-
463
- = 1.4.4 =
464
- * Feature: Editable invoice date per order/invoice.
465
- * Feature: HTML is now allowed in footer and other settings fields.
466
- * Translations: Updated German (Thanks Nadine!)
467
- * Fix: template paths are now saved relative to the site base path (ABSPATH) to prevent errors when moving to another server
468
- * Tweak: Changed bulk action hook for better theme compatibility
469
- * Tweak: Newlines in custom checkout fields
470
-
471
- = 1.4.3 =
472
- * Feature: Added function to call custom fields more easily (see FAQ)
473
- * Feature: Change the my account button text via a filter (wpo_wcpdf_myaccount_button_text)
474
- * Translations: Added Danish (Thanks Mads!)
475
- * Tweak: only load PDF engine if it's not already loaded by another plugin
476
-
477
- = 1.4.2 =
478
- * Fix: Don't create invoice number when exporting packing slips
479
- * Fix: Division by zero for 0 quantity items
480
-
481
- = 1.4.1 =
482
- * Translations: Added Polish (Thanks Mike!)
483
- * Fix: Invoice number formatting notices in debug mode
484
-
485
- = 1.4.0 =
486
- * Feature: Invoice numbers can now be given a prefix, suffix or padding on the settings page!
487
- * Filter: `wpo_wcpdf_email_allowed_statuses` to attach pdf to custom order status emails
488
- * Tweak: Sequential Order Numbers Pro compatibility
489
- * Tweak: Filenames are now automatically sanitized to prevent issues with illegal characters
490
-
491
- = 1.3.2 =
492
- * Fix: error on wpo_wcpdf_email_attachment filter when $pdf_path not set
493
-
494
- = 1.3.1 =
495
- * Fix: invoice number was cleared when Order Actions were being used when an invoice number was not set
496
- * Translations: Updated Slovak (Thanks Jozef!)
497
- * Translations: Added Czech (Thanks CubiQ!)
498
-
499
- = 1.3.0 =
500
- * Feature: Added 'status' panel for better problem diagnosis
501
- * Tweak: split create & get invoice number calls to prevent slow database calls from causing number skipping
502
- * Translations: Added Romanian (Thanks Leonardo!)
503
- * Translations: Added Slovak (Thanks Oleg!)
504
-
505
- = 1.2.13 =
506
- * Feature: added filter for custom email attachment condition (wpo_wcpdf_custom_email_condition)
507
- * Fix: warning for tax implode
508
-
509
- = 1.2.12 =
510
- * Fix: hyperlink underline (was more like a strikethrough)
511
-
512
- = 1.2.11 =
513
- * Translations: Fixed German spelling error
514
- * Translations: Updated Swedish (Thanks Fredrik!)
515
-
516
- = 1.2.10 =
517
- * Translations: Added Swedish (Thanks Jonathan!)
518
- * Fix: Line-height issue (on some systems, the space between lines was very high)
519
-
520
- = 1.2.9 =
521
- * Fix: bug where 'standard' tax class would not display in some cases
522
- * Fix: bug that caused the totals to jump for some font sizes
523
- * Fix: WC2.1 deprecated totals function
524
- * Fix: If multiple taxes were set up with the same name, only one would display (Simple template was not affected)
525
-
526
- = 1.2.8 =
527
- * Template: Body line-height defined to prevent character jumping with italic texts
528
- * Fix: Open Sans now included in plugin package (fixes font issues for servers with allow_url_fopen disabled)
529
-
530
- = 1.2.7 =
531
- * Translations: POT, DE & NL updated
532
- * Fix: Removed stray span tag in totals table
533
-
534
- = 1.2.6 =
535
- * Translations: Spanish update (thanks prepu!)
536
- * Fix: More advanced checks to determine if a customer can download the invoice (including a status filter)
537
-
538
- = 1.2.5 =
539
- * Feature: Optional Invoice Number column for the orders listing
540
- * Feature: Better support for international characters
541
- * Translations: Added Russian & Ukrainian translation (thanks Oleg!)
542
- * Translations: Updated Spanish (Thanks Manuel!) and Dutch translations & POT file
543
- * Tweak: Memory limit notice
544
- * Tweak: Filename name now includes invoice number (when configured in the settings)
545
-
546
- = 1.2.4 =
547
- * Feature: Set which type of emails you want to attach the invoice to
548
-
549
- = 1.2.3 =
550
- * Feature: Manually edit invoice number on the edit order screen
551
- * Feature: Set the first (/next) invoice number on the settings screen
552
- * Fix: Bug where invoice number would be generated twice due to slow database calls
553
- * Fix: php strict warnings
554
-
555
- = 1.2.2 =
556
- * Feature: Simple template now uses Open Sans to include more international special characters
557
- * 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))
558
- * Tweak: PDF engine updated (dompdf 0.6.0)
559
- * 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).
560
-
561
- = 1.2.1 =
562
- * Fix: shipping & fees functions didn't output correctly with the tax set to 'incl'
563
-
564
- = 1.2.0 =
565
- * Feature: Sequential invoice numbers (set upon invoice creation).
566
- * Feature: Invoice date (set upon invoice creation).
567
-
568
- = 1.1.6 =
569
- * Feature: Hungarian translations added - thanks Joseph!
570
- * Tweak: Better debug code.
571
- * Tweak: Error reporting when templates not found.
572
- * Fix: tax rate calculation for free items.
573
-
574
- = 1.1.5 =
575
- * Feature: German translations added - thanks Christian!
576
- * Fix: dompdf 0.6.0 proved to be less stable, so switching back to beta3 for now.
577
-
578
- = 1.1.4 =
579
- * Fix: Template paths on windows servers were not properly saved (stripslashes), resulting in an empty output.
580
-
581
- = 1.1.3 =
582
- * Feature: PDF engine (dompdf) updated to 0.6.0 for better stability and utf-8 support.
583
- * Tweak: Local server path is used for header image for better compatibility with server settings.
584
- * Fix: several small bugs.
585
-
586
- = 1.1.2 =
587
- * Feature: Totals can now be called with simpler template functions
588
- * Feature: Italian translations - thanks max66max!
589
- * Tweak: improved memory performance
590
-
591
- = 1.1.1 =
592
- * Feature: French translations - thanks Guillaume!
593
-
594
- = 1.1.0 =
595
- * Feature: Fees can now also be called ex. VAT
596
- * Feature: Invoices can now be downloaded from the My Account page
597
- * Feature: Spanish translation & POT file included
598
- * Fix: ternary statements that caused an error
599
-
600
- = 1.0.1 =
601
- * Tweak: Packing slip now displays shipping address instead of billing address
602
- * Tweak: Variation data is now displayed by default
603
-
604
- = 1.0.0 =
605
- * First release
606
-
607
- == Upgrade Notice ==
608
-
609
- = 1.5 =
610
- 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.5
6
+ Stable tag: 1.5.32
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.32 =
239
+ * Fix: Updated currency font with Indian Rupee symbol
240
+ * Translations: added Formal German (currently a copy of informal German)
241
+
242
+ = 1.5.31 =
243
+ * Feature: [invoice_day] or [order_day] in invoice number format
244
+ * Fix: Link to hide all ads when premium extensions active
245
+
246
+ = 1.5.30 =
247
+ * Feature: Enable currency font for extended currency support
248
+ * Fix: Font sync on plugin update
249
+
250
+ = 1.5.29 =
251
+ * Translations: Added Croation (Thanks Neven/Spine ICT!), updated French (Thanks Sabra!)
252
+ * Tweak: filter shop address before checking if it's empty
253
+ * Dev: added $order to `wpo_wcpdf_template_file` filter
254
+
255
+ = 1.5.28 =
256
+ * 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.
257
+ * Fix: Bulk actions plugin conflicts
258
+ * Experimental: page numbers (use {{PAGE_NUM}} / {{PAGE_COUNT}} in your template)
259
+
260
+ = 1.5.27 =
261
+ * Feature: Use [invoice_year] and [invoice_month] placeholders in invoice number prefix/suffix
262
+ * Feature: WooCommerce Order Status & Actions Manager emails compatibility
263
+ * Feature: Add invoice number to WC REST API
264
+ * Fix: Allow positive 'discounts' (price corrections)
265
+ * Fix: Discounts rounding
266
+ * Translations: Updated Finnish & Portugese & POT
267
+
268
+ = 1.5.26 =
269
+ * Feature: Automatically list all emails registered in WooCommerce
270
+ * Feature: Reset invoice number yearly
271
+ * Feature: WooCommerce Chained Products compatibility
272
+ * Feature: WooCommerce Product Bundles visibility settings taken into account in invoice
273
+ * Fix: Disable PDF creation from trashed order_ids
274
+ * Tweak: Alert when no orders selected for bulk export (Props to Dartui!)
275
+ * Tweak: PDF invoice settings always under WooCommerce menu (also for premium users)
276
+ * Tweak: extra $item_id passed in row class filter
277
+ * Translations: Updated Slovenian, Spanish, Dutch & POT file
278
+
279
+ = 1.5.24 =
280
+ * Hotfix: Subscriptions renewal filter arguments
281
+
282
+ = 1.5.23 =
283
+ * Fix: WooCommerce Subscriptons 2.0 deprecation notice.
284
+ * Tweak: better qTranslate-X support
285
+ * Tweak: filter for user privileges check (wpo_wcpdf_check_privs)
286
+ * Translations: French translations fix
287
+
288
+ = 1.5.22 =
289
+ * Fix: Workaround for bug in WPML (which cleared all settings)
290
+ * Translation: fixed Polish translation for invoice
291
+
292
+ = 1.5.21 =
293
+ * Translations: Added Estionan (thanks Tanel!)
294
+ * Tweak: WC2.4 compatibility
295
+
296
+ = 1.5.20 =
297
+ * Feature: Option to 'never' display My Account invoice link
298
+ * Fix: Order total for refunds in WC2.4
299
+ * Fix: notice when no custom statuses selected for My Account display
300
+ * Tweak: Product bundles styles
301
+
302
+ = 1.5.19 =
303
+ * Fix: Invoice number search (broke other custom searches)
304
+
305
+ = 1.5.18 =
306
+ * Fix: wpo_wcpdf_item_row_class packing slip filter arguments
307
+
308
+ = 1.5.17 =
309
+ * Feature: WooCommerce Product Bundles compatibility styles
310
+ * Tweak: wpo_wcpdf_item_row_class as filter instead of action
311
+
312
+ = 1.5.16 =
313
+ * Feature: Search orders by invoice number (note: search on formatted invoice number only works for new orders)
314
+ * Feature: Formatted invoice number stored in order
315
+ * Tweak: Function parameters added to some of the filters
316
+ * Tweak: WooCommerce 2.4 compatibility
317
+ * Dev feature: action to add class to items table row (wpo_wcpdf_item_row_class)
318
+ * Translations: Swedish updated (thanks Conney!)
319
+ * Translations: Norwegian updated
320
+
321
+ = 1.5.15 =
322
+ * Fix: invoice number padding didn't work for values lower than 3
323
+ * Tweak: WPML compatibility filter
324
+ * Translations: Updated French (Thanks Nicolas!)
325
+
326
+ = 1.5.14 =
327
+ * Tweak: Invoice number & date edit fields moved to separate box on order edit page
328
+ * Translations: Updated POT & Dutch
329
+
330
+ = 1.5.13 =
331
+ * Fix: Better address comparison to determine when to display alternate address
332
+ * Tweak: Filter N/A addresses
333
+ * Tweak: Use WooCommerce function for 2.3 discounts
334
+ * Translations: Czech Updated (Thanks Ivo!)
335
+ * Translations: French (minor fixes)
336
+
337
+ = 1.5.12 =
338
+ * Translations: added Danish, Updated POT & Italian
339
+
340
+ = 1.5.11 =
341
+ * Fix: Product text attributes (now checks key too)
342
+ * Fix: Status page upload explanation typos
343
+
344
+ = 1.5.10 =
345
+ * Fix: Double check to make sure plugin doesn't attach to user emails
346
+
347
+ = 1.5.9 =
348
+ * Feature: Shorthand function to display product attributes: `$wpo_wcpdf->get_product_attribute( $attribute_name, $product )`
349
+
350
+ = 1.5.8 =
351
+ * Feature: disable invoice for free orders
352
+ * Feature: action to insert data before & after item meta
353
+ * Tweak: Added classes to sku & weight
354
+ * Tweak: Hide payment method from totals (already shown in template)
355
+ * Translations: Updated POT & Dutch
356
+
357
+ = 1.5.7 =
358
+ * Feature: Setting to show email address & phone number on invoice or packing slip (does not work on custom templates based on previous versions!)
359
+
360
+ = 1.5.6 =
361
+ * Feature: Setting to show shipping address on invoice (does not work on custom templates based on previous versions!)
362
+ * Feature: My Account invoice download setting
363
+ * Feature: several new template actions
364
+ * Tweak: WooCommerce Bookings compatibility
365
+ * Tweak: Gerenal stylesheet cleanup
366
+ * Fix: temp path check/error on settings page
367
+ * Fix: Document titles for credit notes and proforma (Pro)
368
+ * Fix: Discount including tax
369
+ * Fix: Special characters on item meta (requires WooCommerce 2.3.6)
370
+ * Translations: Missing text domain on several strings
371
+ * Translations: Updated POT & Dutch
372
+
373
+ = 1.5.5 =
374
+ * Fix: Check for incomplete line tax data (Subscriptions compatibility)
375
+ * Fix: More precise template path instructions
376
+ * Fix: duplicate stylesheet filter
377
+ * Fix: Always prefer original order's billing address for refunds (WooCommerce EU VAT Number compatibility)
378
+ * Translations: Updated German (MwSt. instead of formal Ust.)
379
+ * Translations: Updated Dutch
380
+
381
+ = 1.5.4 =
382
+ * Tweak: include plugin version in style/script includes
383
+ * Tweak: upload code cleanup
384
+ * Fix: Parent invoice number (for Credit Notes in professional extension)
385
+
386
+ = 1.5.3 =
387
+ * Feature: add original order date value to order date filter
388
+ * Feature: Work with line_tax_data when available
389
+ * Feature: pass item_id to items
390
+ * Tweak: later check for woocommerce active
391
+ * Fix: do not try to validate empty settings (Status page settings)
392
+ * Translations: Fixed Dutch typo
393
+
394
+ = 1.5.2 =
395
+ * Fix: fatal error when trying to activate with WooCommerce not installed yet.
396
+ * Tweak: indentation fix on the Simple template
397
+
398
+ = 1.5.1 =
399
+ * Fix: prevent errors when upgrading
400
+
401
+ = 1.5.0 =
402
+ * Feature: All temporary files are now stored centrally in the WP uploads folder.
403
+ * Feature: Debug settings in status panel (output errors & output to HTML)
404
+ * Feature: Compatibility filter for WooCommerce Subscriptions (prevents duplicate invoice numbers)
405
+ * Tweak: Pass order to totals filters
406
+ * Translations: Updated POT
407
+ * Translations: Updated Italian (Thanks Astrid!)
408
+ * Translations: Updated Dutch
409
+ * FAQ: instructions for placing a link on the thank you page
410
+
411
+ = 1.4.14 =
412
+ * Fix: fatal error when user registers at checkout (applies to credit notes only)
413
+ * Translations: Updated German (Thanks Dietmar!)
414
+ * 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.
415
+
416
+ = 1.4.13 =
417
+ * Feature: use separate file for all your template specific functions (template-functions.php)
418
+ * Translations: Added Slovenian (thanks gregy1403!)
419
+ * Translations: Updated Norwegian & Dutch.
420
+ * Translations: Added Japanese - needs custom font!
421
+ * FAQ: instructions on how to use custom fonts
422
+
423
+ = 1.4.12 =
424
+ * Fix: issues with post parent objects (WC2.1 and older)
425
+
426
+ = 1.4.11 =
427
+ * Small fix: bulk actions for specific i18n configurations
428
+ * Tweak: total row key used as class in Simple template
429
+
430
+ = 1.4.10 =
431
+ * Fix: Invoice not attaching
432
+ * Translations: Updated POT file
433
+ * Translations: Updated Dutch, Norwegian, Polish, Brazilian Portugese, Romanian, Russian, Slovak, Spanish & Ukrainian (Many thanks to all the translators!)
434
+ * 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`)
435
+
436
+ = 1.4.9 =
437
+ * Feature: Order number and date are now displayed by default in the Simple template (invoice number and date still optional)
438
+ * Feature: Display Customer/Order notes with a simple shorthand (see FAQ)
439
+ * Translations: Added Brazilian Portugese (thanks Victor Debone!)
440
+ * Tweak: Fail more gracefully when there are errors during PDF generation
441
+ * Tweak: added template type class to template output body
442
+ * Tweak: cleaned up Simple template style.css
443
+
444
+ = 1.4.8 =
445
+ * Translations: Added Finnish (Thanks Sami Mäkelä/Contrast.fi!)
446
+
447
+ = 1.4.7 =
448
+ * Fix: check if image file exists locally, fallback to url if not (CDN compatibility)
449
+ * Fix: make deleting invoice date possible
450
+ * Fix: correct tmp folder check on status page
451
+ * Translations: updated po/mo files
452
+ * Tweak: changed settings capability requirement to `manage_woocommerce` (was: `manage_options`)
453
+ * Tweak: better email attachment function
454
+ * Tweak: prevent footer overlap (Simple template)
455
+ * Tweak: fallback if `glob()` is not allowed on the server
456
+ * Tweak: better custom template instructions (reflects path to actual (child-)theme)
457
+
458
+ = 1.4.6 =
459
+ * HOTFIX: WooCommerce 2.2 compatibility fix
460
+ * Filter for PDF temp folder (wpo_wcpdf_tmp_path)
461
+
462
+ = 1.4.5 =
463
+ * Fix: Double date conversion for order date on invoice number filter (to avoid i18n date issues)
464
+ * Fix: Template selector reset after update
465
+ * Translations: added Norwegian (Thanks Aleksander!)
466
+
467
+ = 1.4.4 =
468
+ * Feature: Editable invoice date per order/invoice.
469
+ * Feature: HTML is now allowed in footer and other settings fields.
470
+ * Translations: Updated German (Thanks Nadine!)
471
+ * Fix: template paths are now saved relative to the site base path (ABSPATH) to prevent errors when moving to another server
472
+ * Tweak: Changed bulk action hook for better theme compatibility
473
+ * Tweak: Newlines in custom checkout fields
474
+
475
+ = 1.4.3 =
476
+ * Feature: Added function to call custom fields more easily (see FAQ)
477
+ * Feature: Change the my account button text via a filter (wpo_wcpdf_myaccount_button_text)
478
+ * Translations: Added Danish (Thanks Mads!)
479
+ * Tweak: only load PDF engine if it's not already loaded by another plugin
480
+
481
+ = 1.4.2 =
482
+ * Fix: Don't create invoice number when exporting packing slips
483
+ * Fix: Division by zero for 0 quantity items
484
+
485
+ = 1.4.1 =
486
+ * Translations: Added Polish (Thanks Mike!)
487
+ * Fix: Invoice number formatting notices in debug mode
488
+
489
+ = 1.4.0 =
490
+ * Feature: Invoice numbers can now be given a prefix, suffix or padding on the settings page!
491
+ * Filter: `wpo_wcpdf_email_allowed_statuses` to attach pdf to custom order status emails
492
+ * Tweak: Sequential Order Numbers Pro compatibility
493
+ * Tweak: Filenames are now automatically sanitized to prevent issues with illegal characters
494
+
495
+ = 1.3.2 =
496
+ * Fix: error on wpo_wcpdf_email_attachment filter when $pdf_path not set
497
+
498
+ = 1.3.1 =
499
+ * Fix: invoice number was cleared when Order Actions were being used when an invoice number was not set
500
+ * Translations: Updated Slovak (Thanks Jozef!)
501
+ * Translations: Added Czech (Thanks CubiQ!)
502
+
503
+ = 1.3.0 =
504
+ * Feature: Added 'status' panel for better problem diagnosis
505
+ * Tweak: split create & get invoice number calls to prevent slow database calls from causing number skipping
506
+ * Translations: Added Romanian (Thanks Leonardo!)
507
+ * Translations: Added Slovak (Thanks Oleg!)
508
+
509
+ = 1.2.13 =
510
+ * Feature: added filter for custom email attachment condition (wpo_wcpdf_custom_email_condition)
511
+ * Fix: warning for tax implode
512
+
513
+ = 1.2.12 =
514
+ * Fix: hyperlink underline (was more like a strikethrough)
515
+
516
+ = 1.2.11 =
517
+ * Translations: Fixed German spelling error
518
+ * Translations: Updated Swedish (Thanks Fredrik!)
519
+
520
+ = 1.2.10 =
521
+ * Translations: Added Swedish (Thanks Jonathan!)
522
+ * Fix: Line-height issue (on some systems, the space between lines was very high)
523
+
524
+ = 1.2.9 =
525
+ * Fix: bug where 'standard' tax class would not display in some cases
526
+ * Fix: bug that caused the totals to jump for some font sizes
527
+ * Fix: WC2.1 deprecated totals function
528
+ * Fix: If multiple taxes were set up with the same name, only one would display (Simple template was not affected)
529
+
530
+ = 1.2.8 =
531
+ * Template: Body line-height defined to prevent character jumping with italic texts
532
+ * Fix: Open Sans now included in plugin package (fixes font issues for servers with allow_url_fopen disabled)
533
+
534
+ = 1.2.7 =
535
+ * Translations: POT, DE & NL updated
536
+ * Fix: Removed stray span tag in totals table
537
+
538
+ = 1.2.6 =
539
+ * Translations: Spanish update (thanks prepu!)
540
+ * Fix: More advanced checks to determine if a customer can download the invoice (including a status filter)
541
+
542
+ = 1.2.5 =
543
+ * Feature: Optional Invoice Number column for the orders listing
544
+ * Feature: Better support for international characters
545
+ * Translations: Added Russian & Ukrainian translation (thanks Oleg!)
546
+ * Translations: Updated Spanish (Thanks Manuel!) and Dutch translations & POT file
547
+ * Tweak: Memory limit notice
548
+ * Tweak: Filename name now includes invoice number (when configured in the settings)
549
+
550
+ = 1.2.4 =
551
+ * Feature: Set which type of emails you want to attach the invoice to
552
+
553
+ = 1.2.3 =
554
+ * Feature: Manually edit invoice number on the edit order screen
555
+ * Feature: Set the first (/next) invoice number on the settings screen
556
+ * Fix: Bug where invoice number would be generated twice due to slow database calls
557
+ * Fix: php strict warnings
558
+
559
+ = 1.2.2 =
560
+ * Feature: Simple template now uses Open Sans to include more international special characters
561
+ * 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))
562
+ * Tweak: PDF engine updated (dompdf 0.6.0)
563
+ * 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).
564
+
565
+ = 1.2.1 =
566
+ * Fix: shipping & fees functions didn't output correctly with the tax set to 'incl'
567
+
568
+ = 1.2.0 =
569
+ * Feature: Sequential invoice numbers (set upon invoice creation).
570
+ * Feature: Invoice date (set upon invoice creation).
571
+
572
+ = 1.1.6 =
573
+ * Feature: Hungarian translations added - thanks Joseph!
574
+ * Tweak: Better debug code.
575
+ * Tweak: Error reporting when templates not found.
576
+ * Fix: tax rate calculation for free items.
577
+
578
+ = 1.1.5 =
579
+ * Feature: German translations added - thanks Christian!
580
+ * Fix: dompdf 0.6.0 proved to be less stable, so switching back to beta3 for now.
581
+
582
+ = 1.1.4 =
583
+ * Fix: Template paths on windows servers were not properly saved (stripslashes), resulting in an empty output.
584
+
585
+ = 1.1.3 =
586
+ * Feature: PDF engine (dompdf) updated to 0.6.0 for better stability and utf-8 support.
587
+ * Tweak: Local server path is used for header image for better compatibility with server settings.
588
+ * Fix: several small bugs.
589
+
590
+ = 1.1.2 =
591
+ * Feature: Totals can now be called with simpler template functions
592
+ * Feature: Italian translations - thanks max66max!
593
+ * Tweak: improved memory performance
594
+
595
+ = 1.1.1 =
596
+ * Feature: French translations - thanks Guillaume!
597
+
598
+ = 1.1.0 =
599
+ * Feature: Fees can now also be called ex. VAT
600
+ * Feature: Invoices can now be downloaded from the My Account page
601
+ * Feature: Spanish translation & POT file included
602
+ * Fix: ternary statements that caused an error
603
+
604
+ = 1.0.1 =
605
+ * Tweak: Packing slip now displays shipping address instead of billing address
606
+ * Tweak: Variation data is now displayed by default
607
+
608
+ = 1.0.0 =
609
+ * First release
610
+
611
+ == Upgrade Notice ==
612
+
613
+ = 1.5 =
614
+ 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,989 +1,989 @@
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.31
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.31';
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($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
- // remove refund lines (shouldn't be in invoice)
719
- foreach ( $totals as $key => $total ) {
720
- if ( strpos($key, 'refund_') !== false ) {
721
- unset( $totals[$key] );
722
- }
723
- }
724
-
725
- return apply_filters( 'wpo_wcpdf_woocommerce_totals', $totals, $this->export->order );
726
- }
727
-
728
- /**
729
- * Return/show the order subtotal
730
- */
731
- public function get_order_subtotal( $tax = 'excl', $discount = 'incl' ) { // set $tax to 'incl' to include tax, same for $discount
732
- //$compound = ($discount == 'incl')?true:false;
733
-
734
- $subtotal = $this->export->order->get_subtotal_to_display( false, $tax );
735
-
736
- $subtotal = ($pos = strpos($subtotal, ' <small>')) ? substr($subtotal, 0, $pos) : $subtotal; //removing the 'excluding tax' text
737
-
738
- $subtotal = array (
739
- 'label' => __('Subtotal', 'wpo_wcpdf'),
740
- 'value' => $subtotal,
741
- );
742
-
743
- return apply_filters( 'wpo_wcpdf_order_subtotal', $subtotal, $tax, $discount );
744
- }
745
- public function order_subtotal( $tax = 'excl', $discount = 'incl' ) {
746
- $subtotal = $this->get_order_subtotal( $tax, $discount );
747
- echo $subtotal['value'];
748
- }
749
-
750
- /**
751
- * Return/show the order shipping costs
752
- */
753
- public function get_order_shipping( $tax = 'excl' ) { // set $tax to 'incl' to include tax
754
- if ($tax == 'excl' ) {
755
- $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping );
756
- } else {
757
- $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping + $this->export->order->order_shipping_tax );
758
- }
759
-
760
- $shipping = array (
761
- 'label' => __('Shipping', 'wpo_wcpdf'),
762
- 'value' => $shipping_costs,
763
- 'tax' => $this->export->wc_price( $this->export->order->order_shipping_tax ),
764
- );
765
- return apply_filters( 'wpo_wcpdf_order_shipping', $shipping, $tax );
766
- }
767
- public function order_shipping( $tax = 'excl' ) {
768
- $shipping = $this->get_order_shipping( $tax );
769
- echo $shipping['value'];
770
- }
771
-
772
- /**
773
- * Return/show the total discount
774
- */
775
- public function get_order_discount( $type = 'total', $tax = 'incl' ) {
776
- if ( $tax == 'incl' ) {
777
- switch ($type) {
778
- case 'cart':
779
- // Cart Discount - pre-tax discounts. (deprecated in WC2.3)
780
- $discount_value = $this->export->order->get_cart_discount();
781
- break;
782
- case 'order':
783
- // Order Discount - post-tax discounts. (deprecated in WC2.3)
784
- $discount_value = $this->export->order->get_order_discount();
785
- break;
786
- case 'total':
787
- // Total Discount
788
- if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
789
- $discount_value = $this->export->order->get_total_discount( false ); // $ex_tax = false
790
- } else {
791
- // WC2.2 and older: recalculate to include tax
792
- $discount_value = 0;
793
- $items = $this->export->order->get_items();;
794
- if( sizeof( $items ) > 0 ) {
795
- foreach( $items as $item ) {
796
- $discount_value += ($item['line_subtotal'] + $item['line_subtotal_tax']) - ($item['line_total'] + $item['line_tax']);
797
- }
798
- }
799
- }
800
-
801
- break;
802
- default:
803
- // Total Discount - Cart & Order Discounts combined
804
- $discount_value = $this->export->order->get_total_discount();
805
- break;
806
- }
807
- } else { // calculate discount excluding tax
808
- if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
809
- $discount_value = $this->export->order->get_total_discount( true ); // $ex_tax = true
810
- } else {
811
- // WC2.2 and older: recalculate to exclude tax
812
- $discount_value = 0;
813
-
814
- $items = $this->export->order->get_items();;
815
- if( sizeof( $items ) > 0 ) {
816
- foreach( $items as $item ) {
817
- $discount_value += ($item['line_subtotal'] - $item['line_total']);
818
- }
819
- }
820
- }
821
- }
822
-
823
- $discount = array (
824
- 'label' => __('Discount', 'wpo_wcpdf'),
825
- 'value' => $this->export->wc_price($discount_value),
826
- 'raw_value' => $discount_value,
827
- );
828
-
829
- if ( round( $discount_value, 3 ) != 0 ) {
830
- return apply_filters( 'wpo_wcpdf_order_discount', $discount, $type, $tax );
831
- }
832
- }
833
- public function order_discount( $type = 'total', $tax = 'incl' ) {
834
- $discount = $this->get_order_discount( $type, $tax );
835
- echo $discount['value'];
836
- }
837
-
838
- /**
839
- * Return the order fees
840
- */
841
- public function get_order_fees( $tax = 'excl' ) {
842
- if ( $wcfees = $this->export->order->get_fees() ) {
843
- foreach( $wcfees as $id => $fee ) {
844
- if ($tax == 'excl' ) {
845
- $fee_price = $this->export->wc_price( $fee['line_total'] );
846
- } else {
847
- $fee_price = $this->export->wc_price( $fee['line_total'] + $fee['line_tax'] );
848
- }
849
-
850
- $fees[ $id ] = array(
851
- 'label' => $fee['name'],
852
- 'value' => $fee_price,
853
- 'line_total' => $this->export->wc_price($fee['line_total']),
854
- 'line_tax' => $this->export->wc_price($fee['line_tax'])
855
- );
856
- }
857
- return $fees;
858
- }
859
- }
860
-
861
- /**
862
- * Return the order taxes
863
- */
864
- public function get_order_taxes() {
865
- $tax_label = __( 'VAT', 'wpo_wcpdf' ); // register alternate label translation
866
- $tax_label = __( 'Tax rate', 'wpo_wcpdf' );
867
- $tax_rate_ids = $this->export->get_tax_rate_ids();
868
- if ($this->export->order->get_taxes()) {
869
- foreach ( $this->export->order->get_taxes() as $key => $tax ) {
870
- $taxes[ $key ] = array(
871
- 'label' => isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ],
872
- 'value' => $this->export->wc_price( ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] ) ),
873
- 'rate_id' => $tax['rate_id'],
874
- 'tax_amount' => $tax['tax_amount'],
875
- 'shipping_tax_amount' => $tax['shipping_tax_amount'],
876
- 'rate' => isset( $tax_rate_ids[ $tax['rate_id'] ] ) ? ( (float) $tax_rate_ids[$tax['rate_id']]['tax_rate'] ) . ' %': '',
877
- );
878
- }
879
-
880
- return apply_filters( 'wpo_wcpdf_order_taxes', $taxes );
881
- }
882
- }
883
-
884
- /**
885
- * Return/show the order grand total
886
- */
887
- public function get_order_grand_total( $tax = 'incl' ) {
888
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
889
- // WC 2.1 or newer is used
890
- $total_unformatted = $this->export->order->get_total();
891
- } else {
892
- // Backwards compatibility
893
- $total_unformatted = $this->export->order->get_order_total();
894
- }
895
-
896
- if ($tax == 'excl' ) {
897
- $total_tax = 0;
898
- foreach ( $this->export->order->get_taxes() as $tax ) {
899
- $total_tax += ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] );
900
- }
901
-
902
- $total = $this->export->wc_price( ( $total_unformatted - $total_tax ) );
903
- $label = __( 'Total ex. VAT', 'wpo_wcpdf' );
904
- } else {
905
- $total = $this->export->wc_price( ( $total_unformatted ) );
906
- $label = __( 'Total', 'wpo_wcpdf' );
907
- }
908
-
909
- $grand_total = array(
910
- 'label' => $label,
911
- 'value' => $total,
912
- );
913
-
914
- return apply_filters( 'wpo_wcpdf_order_grand_total', $grand_total, $tax );
915
- }
916
- public function order_grand_total( $tax = 'incl' ) {
917
- $grand_total = $this->get_order_grand_total( $tax );
918
- echo $grand_total['value'];
919
- }
920
-
921
-
922
- /**
923
- * Return/Show shipping notes
924
- */
925
- public function get_shipping_notes() {
926
- $shipping_notes = wpautop( wptexturize( $this->export->order->customer_note ) );
927
- return apply_filters( 'wpo_wcpdf_shipping_notes', $shipping_notes );
928
- }
929
- public function shipping_notes() {
930
- echo $this->get_shipping_notes();
931
- }
932
-
933
-
934
- /**
935
- * Return/Show shop/company footer imprint, copyright etc.
936
- */
937
- public function get_footer() {
938
- if (isset($this->settings->template_settings['footer'])) {
939
- $footer = wpautop( wptexturize( $this->settings->template_settings[ 'footer' ] ) );
940
- return apply_filters( 'wpo_wcpdf_footer', $footer );
941
- }
942
- }
943
- public function footer() {
944
- echo $this->get_footer();
945
- }
946
-
947
- /**
948
- * Return/Show Extra field 1
949
- */
950
- public function get_extra_1() {
951
- if (isset($this->settings->template_settings['extra_1'])) {
952
- $extra_1 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_1' ] ) );
953
- return apply_filters( 'wpo_wcpdf_extra_1', $extra_1 );
954
- }
955
- }
956
- public function extra_1() {
957
- echo $this->get_extra_1();
958
- }
959
-
960
- /**
961
- * Return/Show Extra field 2
962
- */
963
- public function get_extra_2() {
964
- if (isset($this->settings->template_settings['extra_2'])) {
965
- $extra_2 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_2' ] ) );
966
- return apply_filters( 'wpo_wcpdf_extra_2', $extra_2 );
967
- }
968
- }
969
- public function extra_2() {
970
- echo $this->get_extra_2();
971
- }
972
-
973
- /**
974
- * Return/Show Extra field 3
975
- */
976
- public function get_extra_3() {
977
- if (isset($this->settings->template_settings['extra_3'])) {
978
- $extra_3 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_3' ] ) );
979
- return apply_filters( 'wpo_wcpdf_extra_3', $extra_3 );
980
- }
981
- }
982
- public function extra_3() {
983
- echo $this->get_extra_3();
984
- }
985
- }
986
- }
987
-
988
- // Load main plugin class
989
- $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.32
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.32';
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($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
+ // remove refund lines (shouldn't be in invoice)
719
+ foreach ( $totals as $key => $total ) {
720
+ if ( strpos($key, 'refund_') !== false ) {
721
+ unset( $totals[$key] );
722
+ }
723
+ }
724
+
725
+ return apply_filters( 'wpo_wcpdf_woocommerce_totals', $totals, $this->export->order );
726
+ }
727
+
728
+ /**
729
+ * Return/show the order subtotal
730
+ */
731
+ public function get_order_subtotal( $tax = 'excl', $discount = 'incl' ) { // set $tax to 'incl' to include tax, same for $discount
732
+ //$compound = ($discount == 'incl')?true:false;
733
+
734
+ $subtotal = $this->export->order->get_subtotal_to_display( false, $tax );
735
+
736
+ $subtotal = ($pos = strpos($subtotal, ' <small>')) ? substr($subtotal, 0, $pos) : $subtotal; //removing the 'excluding tax' text
737
+
738
+ $subtotal = array (
739
+ 'label' => __('Subtotal', 'wpo_wcpdf'),
740
+ 'value' => $subtotal,
741
+ );
742
+
743
+ return apply_filters( 'wpo_wcpdf_order_subtotal', $subtotal, $tax, $discount );
744
+ }
745
+ public function order_subtotal( $tax = 'excl', $discount = 'incl' ) {
746
+ $subtotal = $this->get_order_subtotal( $tax, $discount );
747
+ echo $subtotal['value'];
748
+ }
749
+
750
+ /**
751
+ * Return/show the order shipping costs
752
+ */
753
+ public function get_order_shipping( $tax = 'excl' ) { // set $tax to 'incl' to include tax
754
+ if ($tax == 'excl' ) {
755
+ $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping );
756
+ } else {
757
+ $shipping_costs = $this->export->wc_price( $this->export->order->order_shipping + $this->export->order->order_shipping_tax );
758
+ }
759
+
760
+ $shipping = array (
761
+ 'label' => __('Shipping', 'wpo_wcpdf'),
762
+ 'value' => $shipping_costs,
763
+ 'tax' => $this->export->wc_price( $this->export->order->order_shipping_tax ),
764
+ );
765
+ return apply_filters( 'wpo_wcpdf_order_shipping', $shipping, $tax );
766
+ }
767
+ public function order_shipping( $tax = 'excl' ) {
768
+ $shipping = $this->get_order_shipping( $tax );
769
+ echo $shipping['value'];
770
+ }
771
+
772
+ /**
773
+ * Return/show the total discount
774
+ */
775
+ public function get_order_discount( $type = 'total', $tax = 'incl' ) {
776
+ if ( $tax == 'incl' ) {
777
+ switch ($type) {
778
+ case 'cart':
779
+ // Cart Discount - pre-tax discounts. (deprecated in WC2.3)
780
+ $discount_value = $this->export->order->get_cart_discount();
781
+ break;
782
+ case 'order':
783
+ // Order Discount - post-tax discounts. (deprecated in WC2.3)
784
+ $discount_value = $this->export->order->get_order_discount();
785
+ break;
786
+ case 'total':
787
+ // Total Discount
788
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
789
+ $discount_value = $this->export->order->get_total_discount( false ); // $ex_tax = false
790
+ } else {
791
+ // WC2.2 and older: recalculate to include tax
792
+ $discount_value = 0;
793
+ $items = $this->export->order->get_items();;
794
+ if( sizeof( $items ) > 0 ) {
795
+ foreach( $items as $item ) {
796
+ $discount_value += ($item['line_subtotal'] + $item['line_subtotal_tax']) - ($item['line_total'] + $item['line_tax']);
797
+ }
798
+ }
799
+ }
800
+
801
+ break;
802
+ default:
803
+ // Total Discount - Cart & Order Discounts combined
804
+ $discount_value = $this->export->order->get_total_discount();
805
+ break;
806
+ }
807
+ } else { // calculate discount excluding tax
808
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.3' ) >= 0 ) {
809
+ $discount_value = $this->export->order->get_total_discount( true ); // $ex_tax = true
810
+ } else {
811
+ // WC2.2 and older: recalculate to exclude tax
812
+ $discount_value = 0;
813
+
814
+ $items = $this->export->order->get_items();;
815
+ if( sizeof( $items ) > 0 ) {
816
+ foreach( $items as $item ) {
817
+ $discount_value += ($item['line_subtotal'] - $item['line_total']);
818
+ }
819
+ }
820
+ }
821
+ }
822
+
823
+ $discount = array (
824
+ 'label' => __('Discount', 'wpo_wcpdf'),
825
+ 'value' => $this->export->wc_price($discount_value),
826
+ 'raw_value' => $discount_value,
827
+ );
828
+
829
+ if ( round( $discount_value, 3 ) != 0 ) {
830
+ return apply_filters( 'wpo_wcpdf_order_discount', $discount, $type, $tax );
831
+ }
832
+ }
833
+ public function order_discount( $type = 'total', $tax = 'incl' ) {
834
+ $discount = $this->get_order_discount( $type, $tax );
835
+ echo $discount['value'];
836
+ }
837
+
838
+ /**
839
+ * Return the order fees
840
+ */
841
+ public function get_order_fees( $tax = 'excl' ) {
842
+ if ( $wcfees = $this->export->order->get_fees() ) {
843
+ foreach( $wcfees as $id => $fee ) {
844
+ if ($tax == 'excl' ) {
845
+ $fee_price = $this->export->wc_price( $fee['line_total'] );
846
+ } else {
847
+ $fee_price = $this->export->wc_price( $fee['line_total'] + $fee['line_tax'] );
848
+ }
849
+
850
+ $fees[ $id ] = array(
851
+ 'label' => $fee['name'],
852
+ 'value' => $fee_price,
853
+ 'line_total' => $this->export->wc_price($fee['line_total']),
854
+ 'line_tax' => $this->export->wc_price($fee['line_tax'])
855
+ );
856
+ }
857
+ return $fees;
858
+ }
859
+ }
860
+
861
+ /**
862
+ * Return the order taxes
863
+ */
864
+ public function get_order_taxes() {
865
+ $tax_label = __( 'VAT', 'wpo_wcpdf' ); // register alternate label translation
866
+ $tax_label = __( 'Tax rate', 'wpo_wcpdf' );
867
+ $tax_rate_ids = $this->export->get_tax_rate_ids();
868
+ if ($this->export->order->get_taxes()) {
869
+ foreach ( $this->export->order->get_taxes() as $key => $tax ) {
870
+ $taxes[ $key ] = array(
871
+ 'label' => isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ],
872
+ 'value' => $this->export->wc_price( ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] ) ),
873
+ 'rate_id' => $tax['rate_id'],
874
+ 'tax_amount' => $tax['tax_amount'],
875
+ 'shipping_tax_amount' => $tax['shipping_tax_amount'],
876
+ 'rate' => isset( $tax_rate_ids[ $tax['rate_id'] ] ) ? ( (float) $tax_rate_ids[$tax['rate_id']]['tax_rate'] ) . ' %': '',
877
+ );
878
+ }
879
+
880
+ return apply_filters( 'wpo_wcpdf_order_taxes', $taxes );
881
+ }
882
+ }
883
+
884
+ /**
885
+ * Return/show the order grand total
886
+ */
887
+ public function get_order_grand_total( $tax = 'incl' ) {
888
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
889
+ // WC 2.1 or newer is used
890
+ $total_unformatted = $this->export->order->get_total();
891
+ } else {
892
+ // Backwards compatibility
893
+ $total_unformatted = $this->export->order->get_order_total();
894
+ }
895
+
896
+ if ($tax == 'excl' ) {
897
+ $total_tax = 0;
898
+ foreach ( $this->export->order->get_taxes() as $tax ) {
899
+ $total_tax += ( $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ] );
900
+ }
901
+
902
+ $total = $this->export->wc_price( ( $total_unformatted - $total_tax ) );
903
+ $label = __( 'Total ex. VAT', 'wpo_wcpdf' );
904
+ } else {
905
+ $total = $this->export->wc_price( ( $total_unformatted ) );
906
+ $label = __( 'Total', 'wpo_wcpdf' );
907
+ }
908
+
909
+ $grand_total = array(
910
+ 'label' => $label,
911
+ 'value' => $total,
912
+ );
913
+
914
+ return apply_filters( 'wpo_wcpdf_order_grand_total', $grand_total, $tax );
915
+ }
916
+ public function order_grand_total( $tax = 'incl' ) {
917
+ $grand_total = $this->get_order_grand_total( $tax );
918
+ echo $grand_total['value'];
919
+ }
920
+
921
+
922
+ /**
923
+ * Return/Show shipping notes
924
+ */
925
+ public function get_shipping_notes() {
926
+ $shipping_notes = wpautop( wptexturize( $this->export->order->customer_note ) );
927
+ return apply_filters( 'wpo_wcpdf_shipping_notes', $shipping_notes );
928
+ }
929
+ public function shipping_notes() {
930
+ echo $this->get_shipping_notes();
931
+ }
932
+
933
+
934
+ /**
935
+ * Return/Show shop/company footer imprint, copyright etc.
936
+ */
937
+ public function get_footer() {
938
+ if (isset($this->settings->template_settings['footer'])) {
939
+ $footer = wpautop( wptexturize( $this->settings->template_settings[ 'footer' ] ) );
940
+ return apply_filters( 'wpo_wcpdf_footer', $footer );
941
+ }
942
+ }
943
+ public function footer() {
944
+ echo $this->get_footer();
945
+ }
946
+
947
+ /**
948
+ * Return/Show Extra field 1
949
+ */
950
+ public function get_extra_1() {
951
+ if (isset($this->settings->template_settings['extra_1'])) {
952
+ $extra_1 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_1' ] ) );
953
+ return apply_filters( 'wpo_wcpdf_extra_1', $extra_1 );
954
+ }
955
+ }
956
+ public function extra_1() {
957
+ echo $this->get_extra_1();
958
+ }
959
+
960
+ /**
961
+ * Return/Show Extra field 2
962
+ */
963
+ public function get_extra_2() {
964
+ if (isset($this->settings->template_settings['extra_2'])) {
965
+ $extra_2 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_2' ] ) );
966
+ return apply_filters( 'wpo_wcpdf_extra_2', $extra_2 );
967
+ }
968
+ }
969
+ public function extra_2() {
970
+ echo $this->get_extra_2();
971
+ }
972
+
973
+ /**
974
+ * Return/Show Extra field 3
975
+ */
976
+ public function get_extra_3() {
977
+ if (isset($this->settings->template_settings['extra_3'])) {
978
+ $extra_3 = nl2br( wptexturize( $this->settings->template_settings[ 'extra_3' ] ) );
979
+ return apply_filters( 'wpo_wcpdf_extra_3', $extra_3 );
980
+ }
981
+ }
982
+ public function extra_3() {
983
+ echo $this->get_extra_3();
984
+ }
985
+ }
986
+ }
987
+
988
+ // Load main plugin class
989
+ $wpo_wcpdf = new WooCommerce_PDF_Invoices();