WooCommerce PDF Invoices & Packing Slips - Version 2.13.0

Version Description

  • New: include dompdf temporary folder in cleanup procedure
  • New: Add CSS row classes for WPC Product Bundles
  • New: filter to override wc_display_item_meta arguments
  • Fix: Prevent errors when server doesn't support .webp image rendering
  • Fix: change invalid default date 0000-00-00 00:00:00 on number store tables
  • Tweak: Don't store non-historical document settings in order meta
  • Templates: New action hook before the document label (wpo_wcpdf_before_document_label)
  • Libraries: updated dompdf to 1.2.0
  • Marked tested up to WP5.9
Download this release

Release Info

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

Code changes from version 2.12.1 to 2.13.0

Files changed (36) hide show
  1. composer.json +1 -1
  2. composer.lock +12 -14
  3. includes/class-wcpdf-install.php +26 -0
  4. includes/class-wcpdf-main.php +75 -19
  5. includes/class-wcpdf-settings-callbacks.php +12 -0
  6. includes/class-wcpdf-settings-debug.php +4 -36
  7. includes/compatibility/class-wcpdf-compatibility-third-party-plugins.php +39 -6
  8. includes/documents/abstract-wcpdf-order-document-methods.php +14 -3
  9. includes/documents/abstract-wcpdf-order-document.php +8 -3
  10. includes/documents/class-wcpdf-invoice.php +2 -1
  11. includes/documents/class-wcpdf-sequential-number-store.php +6 -3
  12. includes/views/dompdf-status.php +6 -0
  13. includes/wcpdf-functions.php +47 -0
  14. readme.txt +14 -3
  15. templates/Simple/invoice.php +2 -0
  16. templates/Simple/packing-slip.php +2 -0
  17. vendor/composer/installed.json +7 -7
  18. vendor/composer/installed.php +5 -5
  19. vendor/dompdf/dompdf/VERSION +1 -1
  20. vendor/dompdf/dompdf/lib/Cpdf.php +5 -5
  21. vendor/dompdf/dompdf/src/Frame/FrameListIterator.php +31 -19
  22. vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php +0 -7
  23. vendor/dompdf/dompdf/src/FrameDecorator/Page.php +10 -15
  24. vendor/dompdf/dompdf/src/FrameDecorator/Table.php +18 -0
  25. vendor/dompdf/dompdf/src/FrameReflower/Block.php +6 -8
  26. vendor/dompdf/dompdf/src/FrameReflower/Inline.php +0 -6
  27. vendor/dompdf/dompdf/src/FrameReflower/Page.php +4 -2
  28. vendor/dompdf/dompdf/src/FrameReflower/Table.php +4 -5
  29. vendor/dompdf/dompdf/src/FrameReflower/TableCell.php +5 -5
  30. vendor/dompdf/dompdf/src/FrameReflower/TableRow.php +4 -4
  31. vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php +4 -5
  32. vendor/dompdf/dompdf/src/FrameReflower/Text.php +4 -3
  33. vendor/dompdf/dompdf/src/Helpers.php +63 -0
  34. vendor/dompdf/dompdf/src/Positioner/Inline.php +3 -1
  35. vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php +5 -5
  36. woocommerce-pdf-invoices-packingslips.php +2 -2
composer.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "require": {
3
- "dompdf/dompdf": "dev-image-size",
4
  "symfony/polyfill-mbstring": "1.20",
5
  "symfony/polyfill-iconv": "1.20.0"
6
  },
1
  {
2
  "require": {
3
+ "dompdf/dompdf": "^1.2",
4
  "symfony/polyfill-mbstring": "1.20",
5
  "symfony/polyfill-iconv": "1.20.0"
6
  },
composer.lock CHANGED
@@ -4,20 +4,20 @@
4
  "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
- "content-hash": "d97e53feb932279d61a9d0683cf43468",
8
  "packages": [
9
  {
10
  "name": "dompdf/dompdf",
11
- "version": "dev-image-size",
12
  "source": {
13
  "type": "git",
14
  "url": "https://github.com/dompdf/dompdf.git",
15
- "reference": "6cb4296cd9b31b0928c5d0651d73977deb27a844"
16
  },
17
  "dist": {
18
  "type": "zip",
19
- "url": "https://api.github.com/repos/dompdf/dompdf/zipball/6cb4296cd9b31b0928c5d0651d73977deb27a844",
20
- "reference": "6cb4296cd9b31b0928c5d0651d73977deb27a844",
21
  "shasum": ""
22
  },
23
  "require": {
@@ -69,9 +69,9 @@
69
  "homepage": "https://github.com/dompdf/dompdf",
70
  "support": {
71
  "issues": "https://github.com/dompdf/dompdf/issues",
72
- "source": "https://github.com/dompdf/dompdf/tree/image-size"
73
  },
74
- "time": "2022-01-17T00:41:06+00:00"
75
  },
76
  {
77
  "name": "phenx/php-font-lib",
@@ -247,12 +247,12 @@
247
  }
248
  },
249
  "autoload": {
250
- "psr-4": {
251
- "Symfony\\Polyfill\\Iconv\\": ""
252
- },
253
  "files": [
254
  "bootstrap.php"
255
- ]
 
 
 
256
  },
257
  "notification-url": "https://packagist.org/downloads/",
258
  "license": [
@@ -380,9 +380,7 @@
380
  "packages-dev": [],
381
  "aliases": [],
382
  "minimum-stability": "stable",
383
- "stability-flags": {
384
- "dompdf/dompdf": 20
385
- },
386
  "prefer-stable": false,
387
  "prefer-lowest": false,
388
  "platform": [],
4
  "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
+ "content-hash": "8a62b914f789a38ee769610fd975c124",
8
  "packages": [
9
  {
10
  "name": "dompdf/dompdf",
11
+ "version": "v1.2.0",
12
  "source": {
13
  "type": "git",
14
  "url": "https://github.com/dompdf/dompdf.git",
15
+ "reference": "60b704331479a69e9bcdb3496da2315b5c4f94fd"
16
  },
17
  "dist": {
18
  "type": "zip",
19
+ "url": "https://api.github.com/repos/dompdf/dompdf/zipball/60b704331479a69e9bcdb3496da2315b5c4f94fd",
20
+ "reference": "60b704331479a69e9bcdb3496da2315b5c4f94fd",
21
  "shasum": ""
22
  },
23
  "require": {
69
  "homepage": "https://github.com/dompdf/dompdf",
70
  "support": {
71
  "issues": "https://github.com/dompdf/dompdf/issues",
72
+ "source": "https://github.com/dompdf/dompdf/tree/v1.2.0"
73
  },
74
+ "time": "2022-02-07T13:02:10+00:00"
75
  },
76
  {
77
  "name": "phenx/php-font-lib",
247
  }
248
  },
249
  "autoload": {
 
 
 
250
  "files": [
251
  "bootstrap.php"
252
+ ],
253
+ "psr-4": {
254
+ "Symfony\\Polyfill\\Iconv\\": ""
255
+ }
256
  },
257
  "notification-url": "https://packagist.org/downloads/",
258
  "license": [
380
  "packages-dev": [],
381
  "aliases": [],
382
  "minimum-stability": "stable",
383
+ "stability-flags": [],
 
 
384
  "prefer-stable": false,
385
  "prefer-lowest": false,
386
  "platform": [],
includes/class-wcpdf-install.php CHANGED
@@ -372,6 +372,32 @@ class Install {
372
  @unlink( trailingslashit( $font_path ) . 'dompdf_font_family_cache.dist.php' );
373
  @unlink( trailingslashit( $font_path ) . 'mustRead.html' );
374
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
376
  }
377
 
372
  @unlink( trailingslashit( $font_path ) . 'dompdf_font_family_cache.dist.php' );
373
  @unlink( trailingslashit( $font_path ) . 'mustRead.html' );
374
  }
375
+
376
+ // 2.12.2-dev-1: change 'date' database table default value to '1000-01-01 00:00:00'
377
+ if ( version_compare( $installed_version, '2.12.2-dev-1', '<' ) ) {
378
+ global $wpdb;
379
+ $documents = WPO_WCPDF()->documents->get_documents( 'all' );
380
+ foreach ( $documents as $document ) {
381
+ if ( is_callable( array( $document, 'get_sequential_number_store' ) ) ) {
382
+ $number_store = $document->get_sequential_number_store();
383
+ if ( ! empty( $number_store ) ) {
384
+ $column_name = 'date';
385
+ $query = $wpdb->query( "ALTER TABLE {$number_store->table_name} ALTER {$column_name} SET DEFAULT '1000-01-01 00:00:00'" );
386
+ if ( $query ) {
387
+ wcpdf_log_error(
388
+ "Default value changed for 'date' column to '1000-01-01 00:00:00' on database table: {$number_store->table_name}",
389
+ 'info'
390
+ );
391
+ } else {
392
+ wcpdf_log_error(
393
+ "An error occurred! The default value for 'date' column couldn't be changed to '1000-01-01 00:00:00' on database table: {$number_store->table_name}",
394
+ 'critical'
395
+ );
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
 
402
  }
403
 
includes/class-wcpdf-main.php CHANGED
@@ -42,7 +42,7 @@ class Main {
42
  add_filter( 'wpo_wcpdf_html_filters', array( $this, 'html_currency_filters' ) );
43
 
44
  // scheduled attachments cleanup (following settings on Status tab)
45
- add_action( 'wp_scheduled_delete', array( $this, 'attachments_cleanup') );
46
 
47
  // remove private data
48
  add_action( 'woocommerce_privacy_remove_order_personal_data_meta', array( $this, 'remove_order_personal_data_meta' ), 10, 1 );
@@ -641,9 +641,13 @@ class Main {
641
 
642
  global $wp_filesystem;
643
 
644
- // check for WP_Filesystem(), is required for copy_dir()
 
 
 
645
  if ( ! WP_Filesystem() ) {
646
- WP_Filesystem();
 
647
  }
648
 
649
  // we have the directories, let's try to copy
@@ -847,35 +851,87 @@ class Main {
847
  }
848
 
849
  /**
850
- * Remove attachments older than 1 week (daily, hooked into wp_scheduled_delete )
851
  */
852
- public function attachments_cleanup() {
853
- if ( !function_exists("glob") || !function_exists('filemtime') ) {
854
- // glob is required
855
  return;
856
  }
857
 
858
-
859
- if ( !isset( WPO_WCPDF()->settings->debug_settings['enable_cleanup'] ) ) {
860
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
861
  }
862
 
 
 
 
863
 
864
- $cleanup_age_days = isset(WPO_WCPDF()->settings->debug_settings['cleanup_days']) ? floatval(WPO_WCPDF()->settings->debug_settings['cleanup_days']) : 7.0;
865
- $delete_timestamp = time() - ( intval ( DAY_IN_SECONDS * $cleanup_age_days ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
866
 
867
- $tmp_path = $this->get_tmp_path('attachments');
 
 
868
 
869
- if ( $files = glob( $tmp_path.'*.pdf' ) ) { // get all pdf files
870
- foreach( $files as $file ) {
871
- if( is_file( $file ) ) {
872
- $file_timestamp = filemtime( $file );
873
- if ( !empty( $file_timestamp ) && $file_timestamp < $delete_timestamp ) {
874
- @unlink($file);
 
 
 
 
875
  }
876
  }
 
 
 
 
 
 
 
 
 
 
877
  }
 
 
878
  }
 
 
879
  }
880
 
881
  /**
42
  add_filter( 'wpo_wcpdf_html_filters', array( $this, 'html_currency_filters' ) );
43
 
44
  // scheduled attachments cleanup (following settings on Status tab)
45
+ add_action( 'wp_scheduled_delete', array( $this, 'schedule_temporary_files_cleanup' ) );
46
 
47
  // remove private data
48
  add_action( 'woocommerce_privacy_remove_order_personal_data_meta', array( $this, 'remove_order_personal_data_meta' ), 10, 1 );
641
 
642
  global $wp_filesystem;
643
 
644
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
645
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
646
+ }
647
+
648
  if ( ! WP_Filesystem() ) {
649
+ wcpdf_log_error( "WP_Filesystem couldn't be initiated! Unable to copy directory contents.", 'critical' );
650
+ return;
651
  }
652
 
653
  // we have the directories, let's try to copy
851
  }
852
 
853
  /**
854
+ * Schedule temporary files cleanup from paths older than 1 week (daily, hooked into wp_scheduled_delete )
855
  */
856
+ public function schedule_temporary_files_cleanup() {
857
+ if ( ! isset( WPO_WCPDF()->settings->debug_settings['enable_cleanup'] ) ) {
 
858
  return;
859
  }
860
 
861
+ $cleanup_age_days = isset( WPO_WCPDF()->settings->debug_settings['cleanup_days'] ) ? floatval( WPO_WCPDF()->settings->debug_settings['cleanup_days'] ) : 7.0;
862
+ $delete_timestamp = time() - ( intval ( DAY_IN_SECONDS * $cleanup_age_days ) );
863
+ $this->temporary_files_cleanup( $delete_timestamp );
864
+ }
865
+
866
+ /**
867
+ * Temporary files cleanup from paths
868
+ * @param int $delete_timestamp timestamp of the date/time before which to clean up files
869
+ *
870
+ * @return array Output message
871
+ */
872
+ public function temporary_files_cleanup( $delete_timestamp = 0 ) {
873
+ global $wp_filesystem;
874
+
875
+ $delete_before = ! empty( $delete_timestamp ) ? intval( $delete_timestamp ) : time();
876
+
877
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
878
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
879
  }
880
 
881
+ if ( ! WP_Filesystem() ) {
882
+ return array( 'error' => esc_html__( "WP_Filesystem couldn't be initiated!", 'woocommerce-pdf-invoices-packing-slips' ) );
883
+ }
884
 
885
+ $paths_to_cleanup = apply_filters( 'wpo_wcpdf_cleanup_tmp_paths', array(
886
+ $this->get_tmp_path( 'attachments' ),
887
+ $this->get_tmp_path( 'dompdf' ),
888
+ ) );
889
+ $excluded_files = apply_filters( 'wpo_wcpdf_cleanup_excluded_files', array(
890
+ 'index.php',
891
+ '.htaccess',
892
+ ) );
893
+ $folders_level = apply_filters( 'wpo_wcpdf_cleanup_folders_level', 3 );
894
+ $files = array();
895
+ $success = 0;
896
+ $error = 0;
897
+ $output = array();
898
+
899
+ foreach ( $paths_to_cleanup as $path ) {
900
+ $files = array_merge( $files, list_files( $path, $folders_level ) );
901
+ }
902
 
903
+ if ( ! empty( $files ) ) {
904
+ foreach ( $files as $file ) {
905
+ $basename = wp_basename( $file );
906
 
907
+ if ( ! in_array( $basename, $excluded_files ) && $wp_filesystem->exists( $file ) ) {
908
+ $file_timestamp = $wp_filesystem->mtime( $file );
909
+
910
+ // delete file
911
+ if ( $file_timestamp < $delete_before ) {
912
+ if ( $wp_filesystem->delete( $file, true ) ) {
913
+ $success++;
914
+ } else {
915
+ $error++;
916
+ }
917
  }
918
  }
919
+
920
+ if ( $error > 0 ) {
921
+ /* translators: 1,2. file count */
922
+ $message = sprintf( esc_html__( 'Unable to delete %1$d files! (deleted %2$d)', 'woocommerce-pdf-invoices-packing-slips' ), $error, $success );
923
+ $output['error'] = $message;
924
+ } else {
925
+ /* translators: file count */
926
+ $message = sprintf( esc_html__( 'Successfully deleted %d files!', 'woocommerce-pdf-invoices-packing-slips' ), $success );
927
+ $output['success'] = $message;
928
+ }
929
  }
930
+ } else {
931
+ $output['success'] = esc_html__( 'Nothing to delete!', 'woocommerce-pdf-invoices-packing-slips' );
932
  }
933
+
934
+ return $output;
935
  }
936
 
937
  /**
includes/class-wcpdf-settings-callbacks.php CHANGED
@@ -122,6 +122,7 @@ class Settings_Callbacks {
122
  'size' => isset( $args['text_input_size'] ) ? $args['text_input_size'] : NULL,
123
  ) + $args;
124
  unset( $input_args['current'] );
 
125
 
126
  ob_start();
127
  $this->text_input( $input_args );
@@ -390,6 +391,17 @@ class Settings_Callbacks {
390
  // don't display resolution
391
  }
392
 
 
 
 
 
 
 
 
 
 
 
 
393
  printf( '<img src="%1$s" style="display:block" id="img-%2$s"/>', esc_attr( $attachment_src ), esc_attr( $id ) );
394
  if ( ! empty( $attachment_height ) && ! empty( $in_height ) ) {
395
  $attachment_resolution = round( absint( $attachment_height ) / $in_height );
122
  'size' => isset( $args['text_input_size'] ) ? $args['text_input_size'] : NULL,
123
  ) + $args;
124
  unset( $input_args['current'] );
125
+ unset( $input_args['setting_name'] );
126
 
127
  ob_start();
128
  $this->text_input( $input_args );
391
  // don't display resolution
392
  }
393
 
394
+ /*
395
+ * .webp support can be disabled but still showing the image in settings.
396
+ * We should add a notice because this will display an error when redering the PDF using DOMPDF.
397
+ */
398
+ if ( 'webp' === wp_check_filetype( $attachment_src )['ext'] && ! function_exists( 'imagecreatefromwebp' ) ) {
399
+ printf(
400
+ '<div class="notice notice-warning inline" style="display:inline-block; width:auto;"><p>%s</p></div>',
401
+ wp_kses_post( 'File type <strong>webp</strong> is not supported by your server! Please check your <strong>System Configurations</strong> under the <strong>Status</strong> tab.', 'woocommerce-pdf-invoices-packing-slips' )
402
+ );
403
+ }
404
+
405
  printf( '<img src="%1$s" style="display:block" id="img-%2$s"/>', esc_attr( $attachment_src ), esc_attr( $id ) );
406
  if ( ! empty( $attachment_height ) && ! empty( $in_height ) ) {
407
  $attachment_resolution = round( absint( $attachment_height ) / $in_height );
includes/class-wcpdf-settings-debug.php CHANGED
@@ -102,39 +102,10 @@ class Settings_Debug {
102
  if ( ! check_admin_referer( 'wpo_wcpdf_debug_tools_action', 'security' ) ) {
103
  return;
104
  }
105
- $tmp_path = WPO_WCPDF()->main->get_tmp_path( 'attachments' );
106
 
107
- if ( ! function_exists( "glob" ) ) {
108
- // glob is disabled
109
- printf('<div class="notice notice-error"><p>%s<br><code>%s</code></p></div>', esc_html__( "Unable to read temporary folder contents!", 'woocommerce-pdf-invoices-packing-slips' ), $tmp_path);
110
- } else {
111
- $success = 0;
112
- $error = 0;
113
- if ( $files = glob( $tmp_path.'*.pdf' ) ) { // get all pdf files
114
- foreach( $files as $file ) {
115
- if( is_file( $file ) ) {
116
- // delete file
117
- if ( unlink( $file ) === true ) {
118
- $success++;
119
- } else {
120
- $error++;
121
- }
122
- }
123
- }
124
-
125
- if ( $error > 0 ) {
126
- /* translators: 1,2. file count */
127
- $message = sprintf( esc_html__( 'Unable to delete %1$d files! (deleted %2$d)', 'woocommerce-pdf-invoices-packing-slips' ), $error, $success );
128
- printf( '<div class="notice notice-error"><p>%s</p></div>', $message );
129
- } else {
130
- /* translators: file count */
131
- $message = sprintf( esc_html__( 'Successfully deleted %d files!', 'woocommerce-pdf-invoices-packing-slips' ), $success );
132
- printf( '<div class="notice notice-success"><p>%s</p></div>', $message );
133
- }
134
- } else {
135
- printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html__( 'Nothing to delete!', 'woocommerce-pdf-invoices-packing-slips' ) );
136
- }
137
- }
138
  }
139
  ?>
140
  </form>
@@ -263,15 +234,12 @@ class Settings_Debug {
263
  'args' => array(
264
  'option_name' => $option_name,
265
  'id' => 'enable_cleanup',
266
- 'disabled' => ( !function_exists("glob") || !function_exists('filemtime') ) ? 1 : NULL,
267
  /* translators: number of days */
268
  'text_input_wrap' => __( "every %s days", 'woocommerce-pdf-invoices-packing-slips' ),
269
  'text_input_size' => 4,
270
  'text_input_id' => 'cleanup_days',
271
  'text_input_default'=> 7,
272
- 'description' => ( function_exists("glob") && function_exists('filemtime') ) ?
273
- __( "Automatically clean up PDF files stored in the temporary folder (used for email attachments)", 'woocommerce-pdf-invoices-packing-slips' ) :
274
- __( '<b>Disabled:</b> The PHP functions glob and filemtime are required for automatic cleanup but not enabled on your server.', 'woocommerce-pdf-invoices-packing-slips' ),
275
  )
276
  ),
277
  array(
102
  if ( ! check_admin_referer( 'wpo_wcpdf_debug_tools_action', 'security' ) ) {
103
  return;
104
  }
 
105
 
106
+ // clean files
107
+ $output = WPO_WCPDF()->main->temporary_files_cleanup( time() );
108
+ printf( '<div class="notice notice-%1$s"><p>%2$s</p></div>', key( $output ), reset( $output ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
  ?>
111
  </form>
234
  'args' => array(
235
  'option_name' => $option_name,
236
  'id' => 'enable_cleanup',
 
237
  /* translators: number of days */
238
  'text_input_wrap' => __( "every %s days", 'woocommerce-pdf-invoices-packing-slips' ),
239
  'text_input_size' => 4,
240
  'text_input_id' => 'cleanup_days',
241
  'text_input_default'=> 7,
242
+ 'description' => __( "Automatically clean up PDF files stored in the temporary folder (used for email attachments)", 'woocommerce-pdf-invoices-packing-slips' ),
 
 
243
  )
244
  ),
245
  array(
includes/compatibility/class-wcpdf-compatibility-third-party-plugins.php CHANGED
@@ -30,6 +30,9 @@ class Third_Party_Plugins {
30
  // WooCommerce Product Bundles compatibility (add row classes)
31
  add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
32
 
 
 
 
33
  // WooCommerce Chained Products compatibility (add row classes)
34
  add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
35
 
@@ -117,13 +120,13 @@ class Third_Party_Plugins {
117
  * @param object $order WC_Order order
118
  * @param int $item_id WooCommerce Item ID
119
  */
120
- public function add_product_bundles_classes ( $classes, $document_type, $order, $item_id = '' ) {
121
  if ( !class_exists('WC_Bundles') ) {
122
  return $classes;
123
  }
124
 
125
- $item_id = !empty($item_id) ? $item_id : $this->get_item_id_from_classes( $classes );
126
- if ( empty($item_id) ) {
127
  return $classes;
128
  }
129
 
@@ -144,13 +147,43 @@ class Third_Party_Plugins {
144
  }
145
 
146
  /**
147
- * WooCommerce Chanined Products
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  * @param string $classes CSS classes for item row (tr)
149
  * @param string $document_type PDF Document type
150
  * @param object $order WC_Order order
151
  * @param int $item_id WooCommerce Item ID
152
  */
153
- public function add_chained_product_class ( $classes, $document_type, $order, $item_id = '' ) {
154
  if ( !class_exists('SA_WC_Chained_Products') && !class_exists('WC_Chained_Products') ) {
155
  return $classes;
156
  }
@@ -174,7 +207,7 @@ class Third_Party_Plugins {
174
  * @param object $order WC_Order order
175
  * @param int $item_id WooCommerce Item ID
176
  */
177
- public function add_composite_product_class ( $classes, $document_type, $order, $item_id = '' ) {
178
  if ( !function_exists('wc_cp_is_composited_order_item') || !function_exists('wc_cp_is_composite_container_order_item') ) {
179
  return $classes;
180
  }
30
  // WooCommerce Product Bundles compatibility (add row classes)
31
  add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_product_bundles_classes' ), 10, 4 );
32
 
33
+ // WPC Bundles compatibility (add row classes)
34
+ add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_wpc_product_bundles_classes' ), 10, 4 );
35
+
36
  // WooCommerce Chained Products compatibility (add row classes)
37
  add_filter( 'wpo_wcpdf_item_row_class', array( $this, 'add_chained_product_class' ), 10, 4 );
38
 
120
  * @param object $order WC_Order order
121
  * @param int $item_id WooCommerce Item ID
122
  */
123
+ public function add_product_bundles_classes ( $classes, $document_type, $order, $item_id = 0 ) {
124
  if ( !class_exists('WC_Bundles') ) {
125
  return $classes;
126
  }
127
 
128
+ $item_id = ! empty( $item_id ) ? $item_id : $this->get_item_id_from_classes( $classes );
129
+ if ( empty( $item_id ) ) {
130
  return $classes;
131
  }
132
 
147
  }
148
 
149
  /**
150
+ * WPC Product Bundles
151
+ * @param string $classes CSS classes for item row (tr)
152
+ * @param string $document_type PDF Document type
153
+ * @param object $order WC_Order order
154
+ * @param int $item_id WooCommerce Item ID
155
+ */
156
+ public function add_wpc_product_bundles_classes ( $classes, $document_type, $order, $item_id = 0 ) {
157
+ if ( ! class_exists( 'WPCleverWoosb' ) ) {
158
+ return $classes;
159
+ }
160
+
161
+ $item_id = ! empty( $item_id ) ? $item_id : $this->get_item_id_from_classes( $classes );
162
+ if ( empty( $item_id ) ) {
163
+ return $classes;
164
+ }
165
+
166
+ // Add row classes
167
+ $refunded_item_id = WCX_Order::get_item_meta( $order, $item_id, '_refunded_item_id', true );
168
+ $class_item_id = ! empty( $refunded_item_id ) ? $refunded_item_id : $item_id;
169
+
170
+ if ( $bundled_by = WCX_Order::get_item_meta( $order, $class_item_id, '_woosb_parent_id', true ) ) {
171
+ $classes = $classes . ' bundled-item';
172
+ } elseif ( $bundled_items = WCX_Order::get_item_meta( $order, $class_item_id, '_woosb_ids', true ) ) {
173
+ $classes = $classes . ' product-bundle';
174
+ }
175
+
176
+ return $classes;
177
+ }
178
+
179
+ /**
180
+ * WooCommerce Chained Products
181
  * @param string $classes CSS classes for item row (tr)
182
  * @param string $document_type PDF Document type
183
  * @param object $order WC_Order order
184
  * @param int $item_id WooCommerce Item ID
185
  */
186
+ public function add_chained_product_class ( $classes, $document_type, $order, $item_id = 0 ) {
187
  if ( !class_exists('SA_WC_Chained_Products') && !class_exists('WC_Chained_Products') ) {
188
  return $classes;
189
  }
207
  * @param object $order WC_Order order
208
  * @param int $item_id WooCommerce Item ID
209
  */
210
+ public function add_composite_product_class ( $classes, $document_type, $order, $item_id = 0 ) {
211
  if ( !function_exists('wc_cp_is_composited_order_item') || !function_exists('wc_cp_is_composite_container_order_item') ) {
212
  return $classes;
213
  }
includes/documents/abstract-wcpdf-order-document-methods.php CHANGED
@@ -622,9 +622,9 @@ abstract class Order_Document_Methods extends Order_Document {
622
 
623
  // Set item meta
624
  if (function_exists('wc_display_item_meta')) { // WC3.0+
625
- $data['meta'] = wc_display_item_meta( $item, array(
626
  'echo' => false,
627
- ) );
628
  } else {
629
  if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
630
  $meta = new \WC_Order_Item_Meta( $item['item_meta'], $product );
@@ -862,7 +862,7 @@ abstract class Order_Document_Methods extends Order_Document {
862
  $contextless_site_url = str_replace(array('http://','https://'), '', trailingslashit(WP_CONTENT_URL));
863
  }
864
  $thumbnail_path = str_replace( $contextless_site_url, trailingslashit( $forwardslash_basepath ), $contextless_thumbnail_url);
865
-
866
  // fallback if thumbnail file doesn't exist
867
  if (apply_filters('wpo_wcpdf_use_path', true) && !file_exists($thumbnail_path)) {
868
  if ($thumbnail_id = $this->get_thumbnail_id( $product ) ) {
@@ -887,6 +887,17 @@ abstract class Order_Document_Methods extends Order_Document {
887
  $thumbnail = $thumbnail_img_tag_url;
888
  }
889
 
 
 
 
 
 
 
 
 
 
 
 
890
  // die($thumbnail);
891
  return $thumbnail;
892
  }
622
 
623
  // Set item meta
624
  if (function_exists('wc_display_item_meta')) { // WC3.0+
625
+ $data['meta'] = wc_display_item_meta( $item, apply_filters( 'wpo_wcpdf_display_item_meta_args', array(
626
  'echo' => false,
627
+ ), $this ) );
628
  } else {
629
  if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
630
  $meta = new \WC_Order_Item_Meta( $item['item_meta'], $product );
862
  $contextless_site_url = str_replace(array('http://','https://'), '', trailingslashit(WP_CONTENT_URL));
863
  }
864
  $thumbnail_path = str_replace( $contextless_site_url, trailingslashit( $forwardslash_basepath ), $contextless_thumbnail_url);
865
+
866
  // fallback if thumbnail file doesn't exist
867
  if (apply_filters('wpo_wcpdf_use_path', true) && !file_exists($thumbnail_path)) {
868
  if ($thumbnail_id = $this->get_thumbnail_id( $product ) ) {
887
  $thumbnail = $thumbnail_img_tag_url;
888
  }
889
 
890
+ /*
891
+ * PHP GD library can be installed but 'webp' support could be disabled,
892
+ * which turns the function 'imagecreatefromwebp()' inexistent,
893
+ * leading to display an error in DOMPDF.
894
+ *
895
+ * Check 'System configuration' in the Status tab for 'webp' support.
896
+ */
897
+ if ( 'webp' === wp_check_filetype( $thumbnail_path )['ext'] && ! function_exists( 'imagecreatefromwebp' ) ) {
898
+ $thumbnail = '';
899
+ }
900
+
901
  // die($thumbnail);
902
  return $thumbnail;
903
  }
includes/documents/abstract-wcpdf-order-document.php CHANGED
@@ -151,7 +151,8 @@ abstract class Order_Document {
151
  if ( $this->storing_settings_enabled() && empty( $order_settings ) && !empty( $this->order ) ) {
152
  // this is either the first time the document is generated, or historical settings are disabled
153
  // in both cases, we store the document settings
154
- WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
 
155
  }
156
 
157
  // display date & display number were checkbox settings but now a select setting that could be set but empty - should behave as 'unchecked'
@@ -174,8 +175,8 @@ abstract class Order_Document {
174
  return apply_filters( 'wpo_wcpdf_document_store_settings', false, $this );
175
  }
176
 
177
- public function get_setting( $key, $default = '' ) {
178
- $non_historical_settings = apply_filters( 'wpo_wcpdf_non_historical_settings', array(
179
  'enabled',
180
  'attach_to_email_ids',
181
  'disable_for_statuses',
@@ -186,6 +187,10 @@ abstract class Order_Document {
186
  'paper_size',
187
  'font_subsetting',
188
  ), $this );
 
 
 
 
189
  if ( in_array( $key, $non_historical_settings ) && isset( $this->latest_settings ) ) {
190
  $setting = isset( $this->latest_settings[$key] ) ? $this->latest_settings[$key] : $default;
191
  } else {
151
  if ( $this->storing_settings_enabled() && empty( $order_settings ) && !empty( $this->order ) ) {
152
  // this is either the first time the document is generated, or historical settings are disabled
153
  // in both cases, we store the document settings
154
+ // exclude non historical settings from being saved in order meta
155
+ WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", array_diff_key( $settings, array_flip( $this->get_non_historical_settings() ) ) );
156
  }
157
 
158
  // display date & display number were checkbox settings but now a select setting that could be set but empty - should behave as 'unchecked'
175
  return apply_filters( 'wpo_wcpdf_document_store_settings', false, $this );
176
  }
177
 
178
+ public function get_non_historical_settings() {
179
+ return apply_filters( 'wpo_wcpdf_non_historical_settings', array(
180
  'enabled',
181
  'attach_to_email_ids',
182
  'disable_for_statuses',
187
  'paper_size',
188
  'font_subsetting',
189
  ), $this );
190
+ }
191
+
192
+ public function get_setting( $key, $default = '' ) {
193
+ $non_historical_settings = $this->get_non_historical_settings();
194
  if ( in_array( $key, $non_historical_settings ) && isset( $this->latest_settings ) ) {
195
  $setting = isset( $this->latest_settings[$key] ) ? $this->latest_settings[$key] : $default;
196
  } else {
includes/documents/class-wcpdf-invoice.php CHANGED
@@ -62,7 +62,8 @@ class Invoice extends Order_Document_Methods {
62
  $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
63
  $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
64
  $settings = (array) $document_settings + (array) $common_settings;
65
- WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
 
66
  }
67
 
68
  if ( isset( $this->settings['display_date'] ) && $this->settings['display_date'] == 'order_date' && !empty( $this->order ) ) {
62
  $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
63
  $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
64
  $settings = (array) $document_settings + (array) $common_settings;
65
+ // exclude non historical settings from being saved in order meta
66
+ WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", array_diff_key( $settings, array_flip( $this->get_non_historical_settings() ) ) );
67
  }
68
 
69
  if ( isset( $this->settings['display_date'] ) && $this->settings['display_date'] == 'order_date' && !empty( $this->order ) ) {
includes/documents/class-wcpdf-sequential-number-store.php CHANGED
@@ -73,15 +73,18 @@ class Sequential_Number_Store {
73
  $sql = "CREATE TABLE {$this->table_name} (
74
  id int(16) NOT NULL AUTO_INCREMENT,
75
  order_id int(16),
76
- date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
77
  calculated_number int (16),
78
  PRIMARY KEY (id)
79
  ) $charset_collate;";
80
 
81
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
82
- $result = dbDelta( $sql );
 
 
 
83
 
84
- return $result;
85
  }
86
 
87
  /**
73
  $sql = "CREATE TABLE {$this->table_name} (
74
  id int(16) NOT NULL AUTO_INCREMENT,
75
  order_id int(16),
76
+ date datetime DEFAULT '1000-01-01 00:00:00' NOT NULL,
77
  calculated_number int (16),
78
  PRIMARY KEY (id)
79
  ) $charset_collate;";
80
 
81
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
82
+ dbDelta( $sql );
83
+
84
+ // catch mysql errors
85
+ wcpdf_catch_db_object_errors( $wpdb );
86
 
87
+ return;
88
  }
89
 
90
  /**
includes/views/dompdf-status.php CHANGED
@@ -29,6 +29,12 @@ $server_configs = apply_filters( 'wpo_wcpdf_server_configs' , array(
29
  'result' => function_exists('imagecreate'),
30
  'fallback' => __( 'Required if you have images in your documents', 'woocommerce-pdf-invoices-packing-slips' ),
31
  ),
 
 
 
 
 
 
32
  // "PCRE" => array(
33
  // "required" => true,
34
  // "value" => phpversion("pcre"),
29
  'result' => function_exists('imagecreate'),
30
  'fallback' => __( 'Required if you have images in your documents', 'woocommerce-pdf-invoices-packing-slips' ),
31
  ),
32
+ 'WebP Support' => array(
33
+ 'required' => __( 'Required when using .webp images', 'woocommerce-pdf-invoices-packing-slips' ),
34
+ 'value' => null,
35
+ 'result' => function_exists('imagecreatefromwebp'),
36
+ 'fallback' => __( 'Required if you have .webp images in your documents', 'woocommerce-pdf-invoices-packing-slips' ),
37
+ ),
38
  // "PCRE" => array(
39
  // "required" => true,
40
  // "value" => phpversion("pcre"),
includes/wcpdf-functions.php CHANGED
@@ -241,4 +241,51 @@ function wcpdf_output_error( $message, $level = 'error', $e = null ) {
241
  */
242
  function wcpdf_date_format( $document = null, $date_type = null ) {
243
  return apply_filters( 'wpo_wcpdf_date_format', wc_date_format(), $document, $date_type );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  }
241
  */
242
  function wcpdf_date_format( $document = null, $date_type = null ) {
243
  return apply_filters( 'wpo_wcpdf_date_format', wc_date_format(), $document, $date_type );
244
+ }
245
+
246
+ /**
247
+ * Catch MySQL errors
248
+ *
249
+ * Inspired from here: https://github.com/johnbillion/query-monitor/blob/d5b622b91f18552e7105e62fa84d3102b08975a4/collectors/db_queries.php#L125-L280
250
+ *
251
+ * With SAVEQUERIES constant defined as 'false', '$wpdb->queries' is empty and '$EZSQL_ERROR' is used instead.
252
+ * Using the Query Monitor plugin, the SAVEQUERIES constant is defined as 'true'
253
+ * More info about this constant can be found here: https://wordpress.org/support/article/debugging-in-wordpress/#savequeries
254
+ *
255
+ * @param object $wpdb
256
+ * @return array errors found
257
+ */
258
+ function wcpdf_catch_db_object_errors( $wpdb ) {
259
+ global $EZSQL_ERROR;
260
+
261
+ $errors = array();
262
+
263
+ // using '$wpdb->queries'
264
+ if ( ! empty( $wpdb->queries ) && is_array( $wpdb->queries ) ) {
265
+ foreach ( $wpdb->queries as $query ) {
266
+ $result = isset( $query['result'] ) ? $query['result'] : null;
267
+
268
+ if ( is_wp_error( $result ) && is_array( $result->errors ) ) {
269
+ foreach ( $result->errors as $error ) {
270
+ $errors[] = reset( $error );
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ // fallback to '$EZSQL_ERROR'
277
+ if ( empty( $errors ) && ! empty( $EZSQL_ERROR ) && is_array( $EZSQL_ERROR ) ) {
278
+ foreach ( $EZSQL_ERROR as $error ) {
279
+ $errors[] = $error['error_str'];
280
+ }
281
+ }
282
+
283
+ // log errors
284
+ if ( ! empty( $errors ) ) {
285
+ foreach ( $errors as $error_message ) {
286
+ wcpdf_log_error( $error_message, 'critical' );
287
+ }
288
+ }
289
+
290
+ return $errors;
291
  }
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: pomegranate, alexmigf, yordansoares, kluver, dpeyou
3
  Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
- Tested up to: 5.8
7
  Requires PHP: 7.1
8
- Stable tag: 2.12.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -27,7 +27,7 @@ This WooCommerce extension automatically adds a PDF invoice to the order confirm
27
  In addition to this, we offer several premium extensions:
28
 
29
  * Create/email PDF Proforma Invoices, Credit Notes (for Refunds), email Packing Slips, automatic upload to Dropbox & more with [WooCommerce PDF Invoices & Packing Slips Professional](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
30
- * 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)
31
  * More advanced & stylish templates with [WooCommerce PDF Invoices & Packing Slips Premium Templates](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)
32
 
33
  = Fully customizable =
@@ -102,6 +102,17 @@ There's a setting on the Status tab of the settings page that allows you to togg
102
 
103
  == Changelog ==
104
 
 
 
 
 
 
 
 
 
 
 
 
105
  = 2.12.1 =
106
  * Fix: Show a feedback notice after saving settings
107
  * Fix: images with min-width/min-height styles rendered tables incorrectly (dompdf patch)
3
  Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
+ Tested up to: 5.9
7
  Requires PHP: 7.1
8
+ Stable tag: 2.13.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
27
  In addition to this, we offer several premium extensions:
28
 
29
  * Create/email PDF Proforma Invoices, Credit Notes (for Refunds), email Packing Slips, automatic upload to Dropbox & more with [WooCommerce PDF Invoices & Packing Slips Professional](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-professional/)
30
+ * 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-printnode-automatic-order-printing/?affiliates=2) (from our partners at Simba Hosting)
31
  * More advanced & stylish templates with [WooCommerce PDF Invoices & Packing Slips Premium Templates](https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-premium-templates/)
32
 
33
  = Fully customizable =
102
 
103
  == Changelog ==
104
 
105
+ = 2.13.0 =
106
+ * New: include dompdf temporary folder in cleanup procedure
107
+ * New: Add CSS row classes for WPC Product Bundles
108
+ * New: filter to override `wc_display_item_meta` arguments
109
+ * Fix: Prevent errors when server doesn't support `.webp` image rendering
110
+ * Fix: change invalid default date 0000-00-00 00:00:00 on number store tables
111
+ * Tweak: Don't store non-historical document settings in order meta
112
+ * Templates: New action hook before the document label (`wpo_wcpdf_before_document_label`)
113
+ * Libraries: updated dompdf to 1.2.0
114
+ * Marked tested up to WP5.9
115
+
116
  = 2.12.1 =
117
  * Fix: Show a feedback notice after saving settings
118
  * Fix: images with min-width/min-height styles rendered tables incorrectly (dompdf patch)
templates/Simple/invoice.php CHANGED
@@ -24,6 +24,8 @@
24
  </tr>
25
  </table>
26
 
 
 
27
  <h1 class="document-type-label">
28
  <?php if ( $this->has_header_logo() ) echo $this->get_title(); ?>
29
  </h1>
24
  </tr>
25
  </table>
26
 
27
+ <?php do_action( 'wpo_wcpdf_before_document_label', $this->get_type(), $this->order ); ?>
28
+
29
  <h1 class="document-type-label">
30
  <?php if ( $this->has_header_logo() ) echo $this->get_title(); ?>
31
  </h1>
templates/Simple/packing-slip.php CHANGED
@@ -24,6 +24,8 @@
24
  </tr>
25
  </table>
26
 
 
 
27
  <h1 class="document-type-label">
28
  <?php if ( $this->has_header_logo() ) echo $this->get_title(); ?>
29
  </h1>
24
  </tr>
25
  </table>
26
 
27
+ <?php do_action( 'wpo_wcpdf_before_document_label', $this->get_type(), $this->order ); ?>
28
+
29
  <h1 class="document-type-label">
30
  <?php if ( $this->has_header_logo() ) echo $this->get_title(); ?>
31
  </h1>
vendor/composer/installed.json CHANGED
@@ -2,17 +2,17 @@
2
  "packages": [
3
  {
4
  "name": "dompdf/dompdf",
5
- "version": "dev-image-size",
6
- "version_normalized": "dev-image-size",
7
  "source": {
8
  "type": "git",
9
  "url": "https://github.com/dompdf/dompdf.git",
10
- "reference": "6cb4296cd9b31b0928c5d0651d73977deb27a844"
11
  },
12
  "dist": {
13
  "type": "zip",
14
- "url": "https://api.github.com/repos/dompdf/dompdf/zipball/6cb4296cd9b31b0928c5d0651d73977deb27a844",
15
- "reference": "6cb4296cd9b31b0928c5d0651d73977deb27a844",
16
  "shasum": ""
17
  },
18
  "require": {
@@ -33,7 +33,7 @@
33
  "ext-imagick": "Improves image processing performance",
34
  "ext-zlib": "Needed for pdf stream compression"
35
  },
36
- "time": "2022-01-17T00:41:06+00:00",
37
  "type": "library",
38
  "installation-source": "dist",
39
  "autoload": {
@@ -66,7 +66,7 @@
66
  "homepage": "https://github.com/dompdf/dompdf",
67
  "support": {
68
  "issues": "https://github.com/dompdf/dompdf/issues",
69
- "source": "https://github.com/dompdf/dompdf/tree/image-size"
70
  },
71
  "install-path": "../dompdf/dompdf"
72
  },
2
  "packages": [
3
  {
4
  "name": "dompdf/dompdf",
5
+ "version": "v1.2.0",
6
+ "version_normalized": "1.2.0.0",
7
  "source": {
8
  "type": "git",
9
  "url": "https://github.com/dompdf/dompdf.git",
10
+ "reference": "60b704331479a69e9bcdb3496da2315b5c4f94fd"
11
  },
12
  "dist": {
13
  "type": "zip",
14
+ "url": "https://api.github.com/repos/dompdf/dompdf/zipball/60b704331479a69e9bcdb3496da2315b5c4f94fd",
15
+ "reference": "60b704331479a69e9bcdb3496da2315b5c4f94fd",
16
  "shasum": ""
17
  },
18
  "require": {
33
  "ext-imagick": "Improves image processing performance",
34
  "ext-zlib": "Needed for pdf stream compression"
35
  },
36
+ "time": "2022-02-07T13:02:10+00:00",
37
  "type": "library",
38
  "installation-source": "dist",
39
  "autoload": {
66
  "homepage": "https://github.com/dompdf/dompdf",
67
  "support": {
68
  "issues": "https://github.com/dompdf/dompdf/issues",
69
+ "source": "https://github.com/dompdf/dompdf/tree/v1.2.0"
70
  },
71
  "install-path": "../dompdf/dompdf"
72
  },
vendor/composer/installed.php CHANGED
@@ -5,7 +5,7 @@
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => '414fad972f91341521c226eff063c845fc228199',
9
  'name' => '__root__',
10
  'dev' => true,
11
  ),
@@ -16,16 +16,16 @@
16
  'type' => 'library',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
- 'reference' => '414fad972f91341521c226eff063c845fc228199',
20
  'dev_requirement' => false,
21
  ),
22
  'dompdf/dompdf' => array(
23
- 'pretty_version' => 'dev-image-size',
24
- 'version' => 'dev-image-size',
25
  'type' => 'library',
26
  'install_path' => __DIR__ . '/../dompdf/dompdf',
27
  'aliases' => array(),
28
- 'reference' => '6cb4296cd9b31b0928c5d0651d73977deb27a844',
29
  'dev_requirement' => false,
30
  ),
31
  'phenx/php-font-lib' => array(
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '655ed247e8fdfed995edd036e8ae37cc61e08b3a',
9
  'name' => '__root__',
10
  'dev' => true,
11
  ),
16
  'type' => 'library',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
+ 'reference' => '655ed247e8fdfed995edd036e8ae37cc61e08b3a',
20
  'dev_requirement' => false,
21
  ),
22
  'dompdf/dompdf' => array(
23
+ 'pretty_version' => 'v1.2.0',
24
+ 'version' => '1.2.0.0',
25
  'type' => 'library',
26
  'install_path' => __DIR__ . '/../dompdf/dompdf',
27
  'aliases' => array(),
28
+ 'reference' => '60b704331479a69e9bcdb3496da2315b5c4f94fd',
29
  'dev_requirement' => false,
30
  ),
31
  'phenx/php-font-lib' => array(
vendor/dompdf/dompdf/VERSION CHANGED
@@ -1 +1 @@
1
- <6cb4296cd>
1
+ 1.2.0
vendor/dompdf/dompdf/lib/Cpdf.php CHANGED
@@ -5637,7 +5637,7 @@ EOT;
5637
  protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte)
5638
  {
5639
  // generate images
5640
- $img = imagecreatefrompng($file);
5641
 
5642
  if ($img === false) {
5643
  return;
@@ -5686,7 +5686,7 @@ EOT;
5686
  $alpha_channel->writeimage($tempfile_alpha);
5687
 
5688
  // Cast to 8bit+palette
5689
- $imgalpha_ = imagecreatefrompng($tempfile_alpha);
5690
  imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
5691
  imagedestroy($imgalpha_);
5692
  imagepng($imgalpha, $tempfile_alpha);
@@ -5699,7 +5699,7 @@ EOT;
5699
  $color_channels->compositeimage($gmagick, \Gmagick::COMPOSITE_COPYBLUE, 0, 0);
5700
  $color_channels->writeimage($tempfile_plain);
5701
 
5702
- $imgplain = imagecreatefrompng($tempfile_plain);
5703
  }
5704
  // Use PECL imagick + ImageMagic to process transparent PNG images
5705
  elseif (extension_loaded("imagick")) {
@@ -5732,7 +5732,7 @@ EOT;
5732
  $alpha_channel->writeImage($tempfile_alpha);
5733
 
5734
  // Cast to 8bit+palette
5735
- $imgalpha_ = imagecreatefrompng($tempfile_alpha);
5736
  imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
5737
  imagedestroy($imgalpha_);
5738
  imagepng($imgalpha, $tempfile_alpha);
@@ -5748,7 +5748,7 @@ EOT;
5748
  $color_channels->compositeImage($imagick, \Imagick::COMPOSITE_COPYBLUE, 0, 0);
5749
  $color_channels->writeImage($tempfile_plain);
5750
 
5751
- $imgplain = imagecreatefrompng($tempfile_plain);
5752
  } else {
5753
  // allocated colors cache
5754
  $allocated_colors = [];
5637
  protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte)
5638
  {
5639
  // generate images
5640
+ $img = @imagecreatefrompng($file);
5641
 
5642
  if ($img === false) {
5643
  return;
5686
  $alpha_channel->writeimage($tempfile_alpha);
5687
 
5688
  // Cast to 8bit+palette
5689
+ $imgalpha_ = @imagecreatefrompng($tempfile_alpha);
5690
  imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
5691
  imagedestroy($imgalpha_);
5692
  imagepng($imgalpha, $tempfile_alpha);
5699
  $color_channels->compositeimage($gmagick, \Gmagick::COMPOSITE_COPYBLUE, 0, 0);
5700
  $color_channels->writeimage($tempfile_plain);
5701
 
5702
+ $imgplain = @imagecreatefrompng($tempfile_plain);
5703
  }
5704
  // Use PECL imagick + ImageMagic to process transparent PNG images
5705
  elseif (extension_loaded("imagick")) {
5732
  $alpha_channel->writeImage($tempfile_alpha);
5733
 
5734
  // Cast to 8bit+palette
5735
+ $imgalpha_ = @imagecreatefrompng($tempfile_alpha);
5736
  imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
5737
  imagedestroy($imgalpha_);
5738
  imagepng($imgalpha, $tempfile_alpha);
5748
  $color_channels->compositeImage($imagick, \Imagick::COMPOSITE_COPYBLUE, 0, 0);
5749
  $color_channels->writeImage($tempfile_plain);
5750
 
5751
+ $imgplain = @imagecreatefrompng($tempfile_plain);
5752
  } else {
5753
  // allocated colors cache
5754
  $allocated_colors = [];
vendor/dompdf/dompdf/src/Frame/FrameListIterator.php CHANGED
@@ -7,44 +7,48 @@ use Dompdf\Frame;
7
  /**
8
  * Linked-list Iterator
9
  *
10
- * Returns children in order and allows for list to change during iteration,
11
- * provided the changes occur to or after the current element
12
  *
13
  * @access private
14
  * @package dompdf
15
  */
16
  class FrameListIterator implements Iterator
17
  {
18
-
19
  /**
20
  * @var Frame
21
  */
22
- protected $_parent;
23
 
24
  /**
25
- * @var Frame
 
 
 
 
 
26
  */
27
- protected $_cur;
28
 
29
  /**
30
  * @var int
31
  */
32
- protected $_num;
33
 
34
  /**
35
  * @param Frame $frame
36
  */
37
  public function __construct(Frame $frame)
38
  {
39
- $this->_parent = $frame;
40
- $this->_cur = $frame->get_first_child();
41
- $this->_num = 0;
42
  }
43
 
44
  public function rewind(): void
45
  {
46
- $this->_cur = $this->_parent->get_first_child();
47
- $this->_num = 0;
 
48
  }
49
 
50
  /**
@@ -52,7 +56,7 @@ class FrameListIterator implements Iterator
52
  */
53
  public function valid(): bool
54
  {
55
- return isset($this->_cur); // && ($this->_cur->get_prev_sibling() === $this->_prev);
56
  }
57
 
58
  /**
@@ -60,7 +64,7 @@ class FrameListIterator implements Iterator
60
  */
61
  public function key(): int
62
  {
63
- return $this->_num;
64
  }
65
 
66
  /**
@@ -68,17 +72,25 @@ class FrameListIterator implements Iterator
68
  */
69
  public function current(): ?Frame
70
  {
71
- return $this->_cur;
72
  }
73
 
74
  public function next(): void
75
  {
76
- $ret = $this->_cur;
77
- if (!$ret) {
78
  return;
79
  }
80
 
81
- $this->_cur = $this->_cur->get_next_sibling();
82
- $this->_num++;
 
 
 
 
 
 
 
 
 
83
  }
84
  }
7
  /**
8
  * Linked-list Iterator
9
  *
10
+ * Returns children in order and allows for the list to change during iteration,
11
+ * provided the changes occur to or after the current element.
12
  *
13
  * @access private
14
  * @package dompdf
15
  */
16
  class FrameListIterator implements Iterator
17
  {
 
18
  /**
19
  * @var Frame
20
  */
21
+ protected $parent;
22
 
23
  /**
24
+ * @var Frame|null
25
+ */
26
+ protected $cur;
27
+
28
+ /**
29
+ * @var Frame|null
30
  */
31
+ protected $prev;
32
 
33
  /**
34
  * @var int
35
  */
36
+ protected $num;
37
 
38
  /**
39
  * @param Frame $frame
40
  */
41
  public function __construct(Frame $frame)
42
  {
43
+ $this->parent = $frame;
44
+ $this->rewind();
 
45
  }
46
 
47
  public function rewind(): void
48
  {
49
+ $this->cur = $this->parent->get_first_child();
50
+ $this->prev = null;
51
+ $this->num = 0;
52
  }
53
 
54
  /**
56
  */
57
  public function valid(): bool
58
  {
59
+ return $this->cur !== null;
60
  }
61
 
62
  /**
64
  */
65
  public function key(): int
66
  {
67
+ return $this->num;
68
  }
69
 
70
  /**
72
  */
73
  public function current(): ?Frame
74
  {
75
+ return $this->cur;
76
  }
77
 
78
  public function next(): void
79
  {
80
+ if ($this->cur === null) {
 
81
  return;
82
  }
83
 
84
+ if ($this->cur->get_parent() === $this->parent) {
85
+ $this->prev = $this->cur;
86
+ $this->cur = $this->cur->get_next_sibling();
87
+ $this->num++;
88
+ } else {
89
+ // Continue from the previous child if the current frame has been
90
+ // moved to another parent
91
+ $this->cur = $this->prev !== null
92
+ ? $this->prev->get_next_sibling()
93
+ : $this->parent->get_first_child();
94
+ }
95
  }
96
  }
vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php CHANGED
@@ -725,13 +725,6 @@ abstract class AbstractFrameDecorator extends Frame
725
  $iter = $iter->get_next_sibling();
726
  $frame->reset();
727
  $split->append_child($frame);
728
-
729
- // recalculate the float offsets
730
- if ($frame instanceof Block) {
731
- foreach ($frame->get_line_boxes() as $line_box) {
732
- $line_box->get_float_offsets();
733
- }
734
- }
735
  }
736
 
737
  $this->get_parent()->split($split, $page_break, $forced);
725
  $iter = $iter->get_next_sibling();
726
  $frame->reset();
727
  $split->append_child($frame);
 
 
 
 
 
 
 
728
  }
729
 
730
  $this->get_parent()->split($split, $page_break, $forced);
vendor/dompdf/dompdf/src/FrameDecorator/Page.php CHANGED
@@ -94,22 +94,16 @@ class Page extends AbstractFrameDecorator
94
  }
95
 
96
  /**
97
- * Set the frame's containing block. Overridden to set $this->bottom_page_edge.
98
- *
99
- * @param float $x
100
- * @param float $y
101
- * @param float $w
102
- * @param float $h
103
  */
104
- function set_containing_block($x = null, $y = null, $w = null, $h = null)
105
  {
106
- parent::set_containing_block($x, $y, $w, $h);
 
 
107
 
108
- if (isset($h)) {
109
- $style = $this->get_style();
110
- $margin_bottom = (float) $style->length_in_pt($style->margin_bottom, $h);
111
- $this->bottom_page_edge = $h - $margin_bottom;
112
- }
113
  }
114
 
115
  /**
@@ -258,7 +252,8 @@ class Page extends AbstractFrameDecorator
258
  $style->padding_top
259
  ], $cbw);
260
 
261
- return $childPos > $contentEdge && $contentEdge <= $this->bottom_page_edge;
 
262
  }
263
 
264
  /**
@@ -580,7 +575,7 @@ class Page extends AbstractFrameDecorator
580
  }
581
 
582
  // Check if $frame flows off the page
583
- if ($max_y <= $this->bottom_page_edge) {
584
  // no: do nothing
585
  return false;
586
  }
94
  }
95
 
96
  /**
97
+ * Calculate the bottom edge of the page area after margins have been
98
+ * applied for the current page.
 
 
 
 
99
  */
100
+ public function calculate_bottom_page_edge(): void
101
  {
102
+ [, , , $cbh] = $this->get_containing_block();
103
+ $style = $this->get_style();
104
+ $margin_bottom = (float) $style->length_in_pt($style->margin_bottom, $cbh);
105
 
106
+ $this->bottom_page_edge = $cbh - $margin_bottom;
 
 
 
 
107
  }
108
 
109
  /**
252
  $style->padding_top
253
  ], $cbw);
254
 
255
+ return Helpers::lengthGreater($childPos, $contentEdge)
256
+ && Helpers::lengthLessOrEqual($contentEdge, $this->bottom_page_edge);
257
  }
258
 
259
  /**
575
  }
576
 
577
  // Check if $frame flows off the page
578
+ if (Helpers::lengthLessOrEqual($max_y, $this->bottom_page_edge)) {
579
  // no: do nothing
580
  return false;
581
  }
vendor/dompdf/dompdf/src/FrameDecorator/Table.php CHANGED
@@ -305,6 +305,12 @@ class Table extends AbstractFrameDecorator
305
  $tbody->append_child($child);
306
  }
307
 
 
 
 
 
 
 
308
  foreach ($this->get_children() as $child) {
309
  $display = $child->get_style()->display;
310
 
@@ -343,6 +349,12 @@ class Table extends AbstractFrameDecorator
343
  $tr->append_child($child);
344
  }
345
 
 
 
 
 
 
 
346
  foreach ($frame->get_children() as $child) {
347
  $this->normalizeRow($child);
348
  }
@@ -376,6 +388,12 @@ class Table extends AbstractFrameDecorator
376
 
377
  $td->append_child($child);
378
  }
 
 
 
 
 
 
379
  }
380
 
381
  //........................................................................
305
  $tbody->append_child($child);
306
  }
307
 
308
+ // Handle empty table: Make sure there is at least one row group
309
+ if (!$this->get_first_child()) {
310
+ $tbody = $this->create_anonymous_child("tbody", "table-row-group");
311
+ $this->append_child($tbody);
312
+ }
313
+
314
  foreach ($this->get_children() as $child) {
315
  $display = $child->get_style()->display;
316
 
349
  $tr->append_child($child);
350
  }
351
 
352
+ // Handle empty row group: Make sure there is at least one row
353
+ if (!$frame->get_first_child()) {
354
+ $tr = $frame->create_anonymous_child("tr", "table-row");
355
+ $frame->append_child($tr);
356
+ }
357
+
358
  foreach ($frame->get_children() as $child) {
359
  $this->normalizeRow($child);
360
  }
388
 
389
  $td->append_child($child);
390
  }
391
+
392
+ // Handle empty row: Make sure there is at least one cell
393
+ if (!$frame->get_first_child()) {
394
+ $td = $frame->create_anonymous_child("td", "table-cell");
395
+ $frame->append_child($td);
396
+ }
397
  }
398
 
399
  //........................................................................
vendor/dompdf/dompdf/src/FrameReflower/Block.php CHANGED
@@ -860,19 +860,17 @@ class Block extends AbstractFrameReflower
860
 
861
  // Set the containing blocks and reflow each child
862
  foreach ($this->_frame->get_children() as $child) {
863
- // Bail out if the page is full
864
- if ($page->is_full()) {
865
- break;
866
- }
867
-
868
  $child->set_containing_block($cb_x, $cb_y, $width, $height);
869
-
870
  $this->process_clear($child);
871
-
872
  $child->reflow($this->_frame);
873
 
 
 
 
874
  // Don't add the child to the line if a page break has occurred
875
- if ($page->check_page_break($child)) {
 
 
876
  break;
877
  }
878
 
860
 
861
  // Set the containing blocks and reflow each child
862
  foreach ($this->_frame->get_children() as $child) {
 
 
 
 
 
863
  $child->set_containing_block($cb_x, $cb_y, $width, $height);
 
864
  $this->process_clear($child);
 
865
  $child->reflow($this->_frame);
866
 
867
+ // Check for a page break before the child
868
+ $page->check_page_break($child);
869
+
870
  // Don't add the child to the line if a page break has occurred
871
+ // before it (possibly via a descendant), in which case it has been
872
+ // reset, including its position
873
+ if ($page->is_full() && $child->get_position("x") === null) {
874
  break;
875
  }
876
 
vendor/dompdf/dompdf/src/FrameReflower/Inline.php CHANGED
@@ -157,12 +157,6 @@ class Inline extends AbstractFrameReflower
157
  foreach ($frame->get_children() as $child) {
158
  $child->set_containing_block($cb);
159
  $child->reflow($block);
160
-
161
- // Stop reflow of subsequent children if the frame was split within
162
- // child reflow
163
- if ($child->get_parent() !== $frame) {
164
- break;
165
- }
166
  }
167
 
168
  // Assume the position of the first child
157
  foreach ($frame->get_children() as $child) {
158
  $child->set_containing_block($cb);
159
  $child->reflow($block);
 
 
 
 
 
 
160
  }
161
 
162
  // Assume the position of the first child
vendor/dompdf/dompdf/src/FrameReflower/Page.php CHANGED
@@ -44,8 +44,8 @@ class Page extends AbstractFrameReflower
44
  }
45
 
46
  /**
47
- * @param Frame $frame
48
- * @param $page_number
49
  */
50
  function apply_page_style(Frame $frame, $page_number)
51
  {
@@ -83,6 +83,8 @@ class Page extends AbstractFrameReflower
83
 
84
  $frame->set_style($style);
85
  }
 
 
86
  }
87
 
88
  /**
44
  }
45
 
46
  /**
47
+ * @param PageFrameDecorator $frame
48
+ * @param int $page_number
49
  */
50
  function apply_page_style(Frame $frame, $page_number)
51
  {
83
 
84
  $frame->set_style($style);
85
  }
86
+
87
+ $frame->calculate_bottom_page_edge();
88
  }
89
 
90
  /**
vendor/dompdf/dompdf/src/FrameReflower/Table.php CHANGED
@@ -412,17 +412,16 @@ class Table extends AbstractFrameReflower
412
 
413
  // Set the containing block of each child & reflow
414
  foreach ($frame->get_children() as $child) {
415
- // Bail if the page is full
416
- if (!$page->in_nested_table() && $page->is_full()) {
417
- break;
418
- }
419
-
420
  $child->set_containing_block($content_x, $content_y, $width, $h);
421
  $child->reflow();
422
 
423
  if (!$page->in_nested_table()) {
424
  // Check if a split has occurred
425
  $page->check_page_break($child);
 
 
 
 
426
  }
427
  }
428
 
412
 
413
  // Set the containing block of each child & reflow
414
  foreach ($frame->get_children() as $child) {
 
 
 
 
 
415
  $child->set_containing_block($content_x, $content_y, $width, $h);
416
  $child->reflow();
417
 
418
  if (!$page->in_nested_table()) {
419
  // Check if a split has occurred
420
  $page->check_page_break($child);
421
+
422
+ if ($page->is_full()) {
423
+ break;
424
+ }
425
  }
426
  }
427
 
vendor/dompdf/dompdf/src/FrameReflower/TableCell.php CHANGED
@@ -90,14 +90,14 @@ class TableCell extends Block
90
 
91
  // Set the containing blocks and reflow each child
92
  foreach ($this->_frame->get_children() as $child) {
93
- if ($page->is_full()) {
94
- break;
95
- }
96
-
97
  $child->set_containing_block($content_x, $content_y, $cb_w, $h);
98
  $this->process_clear($child);
99
  $child->reflow($this->_frame);
100
- $this->process_float($child, $x + $left_space, $w - $right_space - $left_space);
 
 
 
 
101
  }
102
 
103
  // Determine our height
90
 
91
  // Set the containing blocks and reflow each child
92
  foreach ($this->_frame->get_children() as $child) {
 
 
 
 
93
  $child->set_containing_block($content_x, $content_y, $cb_w, $h);
94
  $this->process_clear($child);
95
  $child->reflow($this->_frame);
96
+ $this->process_float($child, $content_x, $cb_w);
97
+
98
+ if ($page->is_full()) {
99
+ break;
100
+ }
101
  }
102
 
103
  // Determine our height
vendor/dompdf/dompdf/src/FrameReflower/TableRow.php CHANGED
@@ -53,12 +53,12 @@ class TableRow extends AbstractFrameReflower
53
  $cb = $this->_frame->get_containing_block();
54
 
55
  foreach ($this->_frame->get_children() as $child) {
56
- if ($page->is_full()) {
57
- return;
58
- }
59
-
60
  $child->set_containing_block($cb);
61
  $child->reflow();
 
 
 
 
62
  }
63
 
64
  if ($page->is_full()) {
53
  $cb = $this->_frame->get_containing_block();
54
 
55
  foreach ($this->_frame->get_children() as $child) {
 
 
 
 
56
  $child->set_containing_block($cb);
57
  $child->reflow();
58
+
59
+ if ($page->is_full()) {
60
+ break;
61
+ }
62
  }
63
 
64
  if ($page->is_full()) {
vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php CHANGED
@@ -44,16 +44,15 @@ class TableRowGroup extends AbstractFrameReflower
44
  $cb = $frame->get_containing_block();
45
 
46
  foreach ($frame->get_children() as $child) {
47
- // Bail if the page is full
48
- if ($page->is_full()) {
49
- break;
50
- }
51
-
52
  $child->set_containing_block($cb["x"], $cb["y"], $cb["w"], $cb["h"]);
53
  $child->reflow();
54
 
55
  // Check if a split has occurred
56
  $page->check_page_break($child);
 
 
 
 
57
  }
58
 
59
  $table = TableFrameDecorator::find_parent_table($frame);
44
  $cb = $frame->get_containing_block();
45
 
46
  foreach ($frame->get_children() as $child) {
 
 
 
 
 
47
  $child->set_containing_block($cb["x"], $cb["y"], $cb["w"], $cb["h"]);
48
  $child->reflow();
49
 
50
  // Check if a split has occurred
51
  $page->check_page_break($child);
52
+
53
+ if ($page->is_full()) {
54
+ break;
55
+ }
56
  }
57
 
58
  $table = TableFrameDecorator::find_parent_table($frame);
vendor/dompdf/dompdf/src/FrameReflower/Text.php CHANGED
@@ -158,7 +158,7 @@ class Text extends AbstractFrameReflower
158
  ], $line_width);
159
  $frame_width = $text_width + $mbp_width;
160
 
161
- if ($frame_width <= $available_width) {
162
  return false;
163
  }
164
 
@@ -181,8 +181,9 @@ class Text extends AbstractFrameReflower
181
  $sep = $words[$i + 1] ?? "";
182
  $word = $sep === " " ? $words[$i] : $words[$i] . $sep;
183
  $word_width = $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $char_spacing);
 
184
 
185
- if ($width + $word_width + $mbp_width > $available_width) {
186
  // If the previous split happened by soft hyphen, we have to
187
  // append its width again because the last hyphen of a line
188
  // won't be removed
@@ -225,7 +226,7 @@ class Text extends AbstractFrameReflower
225
  $c = mb_substr($word, $j, 1);
226
  $w = $fontMetrics->getTextWidth($s . $c, $font, $size, $word_spacing, $char_spacing);
227
 
228
- if ($w > $available_width) {
229
  break;
230
  }
231
 
158
  ], $line_width);
159
  $frame_width = $text_width + $mbp_width;
160
 
161
+ if (Helpers::lengthLessOrEqual($frame_width, $available_width)) {
162
  return false;
163
  }
164
 
181
  $sep = $words[$i + 1] ?? "";
182
  $word = $sep === " " ? $words[$i] : $words[$i] . $sep;
183
  $word_width = $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $char_spacing);
184
+ $used_width = $width + $word_width + $mbp_width;
185
 
186
+ if (Helpers::lengthGreater($used_width, $available_width)) {
187
  // If the previous split happened by soft hyphen, we have to
188
  // append its width again because the last hyphen of a line
189
  // won't be removed
226
  $c = mb_substr($word, $j, 1);
227
  $w = $fontMetrics->getTextWidth($s . $c, $font, $size, $word_spacing, $char_spacing);
228
 
229
+ if (Helpers::lengthGreater($w, $available_width)) {
230
  break;
231
  }
232
 
vendor/dompdf/dompdf/src/Helpers.php CHANGED
@@ -962,4 +962,67 @@ class Helpers
962
 
963
  return $str;
964
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
965
  }
962
 
963
  return $str;
964
  }
965
+
966
+ /**
967
+ * Check whether two lengths should be considered equal, accounting for
968
+ * inaccuracies in float computation.
969
+ *
970
+ * The implementation relies on the fact that we are neither dealing with
971
+ * very large, nor with very small numbers in layout. Adapted from
972
+ * https://floating-point-gui.de/errors/comparison/.
973
+ *
974
+ * @param float $a
975
+ * @param float $b
976
+ *
977
+ * @return bool
978
+ */
979
+ public static function lengthEqual(float $a, float $b): bool
980
+ {
981
+ // The epsilon results in a precision of at least:
982
+ // * 7 decimal digits at around 1
983
+ // * 4 decimal digits at around 1000 (around the size of common paper formats)
984
+ // * 2 decimal digits at around 100,000 (100,000pt ~ 35.28m)
985
+ static $epsilon = 1e-8;
986
+ static $almostZero = 1e-12;
987
+
988
+ $diff = abs($a - $b);
989
+
990
+ if ($a === $b || $diff < $almostZero) {
991
+ return true;
992
+ }
993
+
994
+ return $diff < $epsilon * max(abs($a), abs($b));
995
+ }
996
+
997
+ /**
998
+ * Check `$a < $b`, accounting for inaccuracies in float computation.
999
+ */
1000
+ public static function lengthLess(float $a, float $b): bool
1001
+ {
1002
+ return $a < $b && !self::lengthEqual($a, $b);
1003
+ }
1004
+
1005
+ /**
1006
+ * Check `$a <= $b`, accounting for inaccuracies in float computation.
1007
+ */
1008
+ public static function lengthLessOrEqual(float $a, float $b): bool
1009
+ {
1010
+ return $a <= $b || self::lengthEqual($a, $b);
1011
+ }
1012
+
1013
+ /**
1014
+ * Check `$a > $b`, accounting for inaccuracies in float computation.
1015
+ */
1016
+ public static function lengthGreater(float $a, float $b): bool
1017
+ {
1018
+ return $a > $b && !self::lengthEqual($a, $b);
1019
+ }
1020
+
1021
+ /**
1022
+ * Check `$a >= $b`, accounting for inaccuracies in float computation.
1023
+ */
1024
+ public static function lengthGreaterOrEqual(float $a, float $b): bool
1025
+ {
1026
+ return $a >= $b || self::lengthEqual($a, $b);
1027
+ }
1028
  }
vendor/dompdf/dompdf/src/Positioner/Inline.php CHANGED
@@ -11,6 +11,7 @@ namespace Dompdf\Positioner;
11
  use Dompdf\FrameDecorator\AbstractFrameDecorator;
12
  use Dompdf\FrameDecorator\Inline as InlineFrameDecorator;
13
  use Dompdf\Exception;
 
14
 
15
  /**
16
  * Positions inline frames
@@ -40,8 +41,9 @@ class Inline extends AbstractPositioner
40
  // Atomic inline boxes and replaced inline elements
41
  // (inline-block, inline-table, img etc.)
42
  $width = $frame->get_margin_width();
 
43
 
44
- if ($width > ($cb["w"] - $line->left - $line->w - $line->right)) {
45
  $block->add_line();
46
  $line = $block->get_current_line_box();
47
  }
11
  use Dompdf\FrameDecorator\AbstractFrameDecorator;
12
  use Dompdf\FrameDecorator\Inline as InlineFrameDecorator;
13
  use Dompdf\Exception;
14
+ use Dompdf\Helpers;
15
 
16
  /**
17
  * Positions inline frames
41
  // Atomic inline boxes and replaced inline elements
42
  // (inline-block, inline-table, img etc.)
43
  $width = $frame->get_margin_width();
44
+ $available_width = $cb["w"] - $line->left - $line->w - $line->right;
45
 
46
+ if (Helpers::lengthGreater($width, $available_width)) {
47
  $block->add_line();
48
  $line = $block->get_current_line_box();
49
  }
vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php CHANGED
@@ -278,23 +278,23 @@ abstract class AbstractRenderer
278
  $cpdfFromGd = false;
279
  imagesavealpha($bg, true);
280
  imagealphablending($bg, false);
281
- $src = imagecreatefrompng($img);
282
  break;
283
 
284
  case "jpeg":
285
- $src = imagecreatefromjpeg($img);
286
  break;
287
 
288
  case "webp":
289
- $src = imagecreatefromwebp($img);
290
  break;
291
 
292
  case "gif":
293
- $src = imagecreatefromgif($img);
294
  break;
295
 
296
  case "bmp":
297
- $src = Helpers::imagecreatefrombmp($img);
298
  break;
299
 
300
  default:
278
  $cpdfFromGd = false;
279
  imagesavealpha($bg, true);
280
  imagealphablending($bg, false);
281
+ $src = @imagecreatefrompng($img);
282
  break;
283
 
284
  case "jpeg":
285
+ $src = @imagecreatefromjpeg($img);
286
  break;
287
 
288
  case "webp":
289
+ $src = @imagecreatefromwebp($img);
290
  break;
291
 
292
  case "gif":
293
+ $src = @imagecreatefromgif($img);
294
  break;
295
 
296
  case "bmp":
297
+ $src = @Helpers::imagecreatefrombmp($img);
298
  break;
299
 
300
  default:
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 2.12.1
7
  * Author: WP Overnight
8
  * Author URI: https://www.wpovernight.com
9
  * License: GPLv2 or later
@@ -21,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
21
 
22
  class WPO_WCPDF {
23
 
24
- public $version = '2.12.1';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
  public $legacy_textdomain;
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-slips-bundle/
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 2.13.0
7
  * Author: WP Overnight
8
  * Author URI: https://www.wpovernight.com
9
  * License: GPLv2 or later
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.13.0';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
  public $legacy_textdomain;