WooCommerce PDF Invoices & Packing Slips - Version 2.0.11

Version Description

  • Fix: Improved fonts update routine (now preserves custom fonts)
  • Fix: Enable HTML5 parser by default (fixes issues with libxml)
  • Tweak: Show both PHP & WP Memory limit in Status tab
Download this release

Release Info

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

Code changes from version 2.0.10 to 2.0.11

includes/class-wcpdf-admin.php CHANGED
@@ -41,6 +41,20 @@ class Admin {
41
  return;
42
  }
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  $invoice_count = $this->get_invoice_count();
45
  if ( $invoice_count > 100 ) {
46
  $rounded_count = (int) substr( (string) $invoice_count, 0, 1 ) * pow( 10, strlen( (string) $invoice_count ) - 1);
@@ -50,7 +64,7 @@ class Admin {
50
  <p><?php _e( 'It would mean a lot to us if you would quickly give our plugin a 5-star rating. Help us spread the word and boost our motivation!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
51
  <ul>
52
  <li><a href="https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips/reviews/?rate=5#new-post" class="button"><?php _e( 'Yes you deserve it!', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></a></li>
53
- <li><a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_review', true ) ); ?>" class="wpo-wcpdf-dismiss"><?php _e( 'Already did!', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
54
  <li><a href="mailto:support@wpovernight.com?Subject=Here%20is%20how%20I%20think%20you%20can%20do%20better"><?php _e( 'Actually, I have a complaint...', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
55
  </ul>
56
  </div>
41
  return;
42
  }
43
 
44
+ // keep track of how many days this notice is show so we can remove it after 7 days
45
+ $notice_shown_on = get_option( 'wpo_wcpdf_review_notice_shown', array() );
46
+ $today = date('Y-m-d');
47
+ if ( !in_array($today, $notice_shown_on) ) {
48
+ $notice_shown_on[] = $today;
49
+ update_option( 'wpo_wcpdf_review_notice_shown', $notice_shown_on );
50
+ }
51
+ // count number of days review is shown, dismiss forever if shown more than 7
52
+ if (count($notice_shown_on) > 7) {
53
+ update_option( 'wpo_wcpdf_review_notice_dismissed', true );
54
+ return;
55
+ }
56
+
57
+ // get invoice count to determine whether notice should be shown
58
  $invoice_count = $this->get_invoice_count();
59
  if ( $invoice_count > 100 ) {
60
  $rounded_count = (int) substr( (string) $invoice_count, 0, 1 ) * pow( 10, strlen( (string) $invoice_count ) - 1);
64
  <p><?php _e( 'It would mean a lot to us if you would quickly give our plugin a 5-star rating. Help us spread the word and boost our motivation!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
65
  <ul>
66
  <li><a href="https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips/reviews/?rate=5#new-post" class="button"><?php _e( 'Yes you deserve it!', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></a></li>
67
+ <li><a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_review', true ) ); ?>" class="wpo-wcpdf-dismiss"><?php _e( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ); ?> / <?php _e( 'Already did!', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
68
  <li><a href="mailto:support@wpovernight.com?Subject=Here%20is%20how%20I%20think%20you%20can%20do%20better"><?php _e( 'Actually, I have a complaint...', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
69
  </ul>
70
  </div>
includes/class-wcpdf-install.php CHANGED
@@ -1,309 +1,312 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly
10
- }
11
-
12
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Install' ) ) :
13
-
14
- class Install {
15
-
16
- function __construct() {
17
- // run lifecycle methods
18
- if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
19
- add_action( 'wp_loaded', array( $this, 'do_install' ) );
20
- }
21
- }
22
-
23
- /** Lifecycle methods *******************************************************
24
- * Because register_activation_hook only runs when the plugin is manually
25
- * activated by the user, we're checking the current version against the
26
- * version stored in the database
27
- ****************************************************************************/
28
-
29
- /**
30
- * Handles version checking
31
- */
32
- public function do_install() {
33
- // only install when woocommerce is active
34
- if ( !WPO_WCPDF()->is_woocommerce_activated() ) {
35
- return;
36
- }
37
-
38
- $version_setting = 'wpo_wcpdf_version';
39
- $installed_version = get_option( $version_setting );
40
-
41
- // installed version lower than plugin version?
42
- if ( version_compare( $installed_version, WPO_WCPDF_VERSION, '<' ) ) {
43
-
44
- if ( ! $installed_version ) {
45
- $this->install();
46
- } else {
47
- $this->upgrade( $installed_version );
48
- }
49
-
50
- // new version number
51
- update_option( $version_setting, WPO_WCPDF_VERSION );
52
- } elseif ( $installed_version && version_compare( $installed_version, WPO_WCPDF_VERSION, '>' ) ) {
53
- $this->downgrade( $installed_version );
54
- // downgrade version number
55
- update_option( $version_setting, WPO_WCPDF_VERSION );
56
- }
57
- }
58
-
59
-
60
- /**
61
- * Plugin install method. Perform any installation tasks here
62
- */
63
- protected function install() {
64
- // only install when php 5.3 or higher
65
- if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
66
- return;
67
- }
68
-
69
- // check if upgrading from versionless (1.4.14 and older)
70
- if ( get_option('wpo_wcpdf_general_settings') ) {
71
- $this->upgrade( 'versionless' );
72
- return;
73
- }
74
-
75
- // Create temp folders
76
- $tmp_base = WPO_WCPDF()->main->get_tmp_base();
77
-
78
- // check if tmp folder exists => if not, initialize
79
- if ( !@is_dir( $tmp_base ) ) {
80
- WPO_WCPDF()->main->init_tmp( $tmp_base );
81
- }
82
-
83
- // set default settings
84
- $settings_defaults = array(
85
- 'wpo_wcpdf_settings_general' => array(
86
- 'download_display' => 'display',
87
- 'template_path' => WPO_WCPDF()->plugin_path() . '/templates/Simple',
88
- // 'currency_font' => '',
89
- 'paper_size' => 'a4',
90
- // 'header_logo' => '',
91
- // 'shop_name' => array(),
92
- // 'shop_address' => array(),
93
- // 'footer' => array(),
94
- // 'extra_1' => array(),
95
- // 'extra_2' => array(),
96
- // 'extra_3' => array(),
97
- ),
98
- 'wpo_wcpdf_documents_settings_invoice' => array(
99
- 'enabled' => 1,
100
- // 'attach_to_email_ids' => array(),
101
- // 'display_shipping_address' => '',
102
- // 'display_email' => '',
103
- // 'display_phone' => '',
104
- // 'display_date' => '',
105
- // 'display_number' => '',
106
- // 'number_format' => array(),
107
- // 'reset_number_yearly' => '',
108
- // 'my_account_buttons' => '',
109
- // 'invoice_number_column' => '',
110
- // 'disable_free' => '',
111
- ),
112
- 'wpo_wcpdf_documents_settings_packing-slip' => array(
113
- 'enabled' => 1,
114
- // 'display_billing_address' => '',
115
- // 'display_email' => '',
116
- // 'display_phone' => '',
117
- ),
118
- // 'wpo_wcpdf_settings_debug' => array(
119
- // 'legacy_mode' => '',
120
- // 'enable_debug' => '',
121
- // 'html_output' => '',
122
- // ),
123
- );
124
- foreach ($settings_defaults as $option => $defaults) {
125
- update_option( $option, $defaults );
126
- }
127
- }
128
-
129
- /**
130
- * Plugin upgrade method. Perform any required upgrades here
131
- *
132
- * @param string $installed_version the currently installed ('old') version
133
- */
134
- protected function upgrade( $installed_version ) {
135
- // only upgrade when php 5.3 or higher
136
- if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
137
- return;
138
- }
139
-
140
- // sync fonts on every upgrade!
141
- $tmp_base = WPO_WCPDF()->main->get_tmp_base();
142
-
143
- // check if tmp folder exists => if not, initialize
144
- if ( !@is_dir( $tmp_base ) ) {
145
- WPO_WCPDF()->main->init_tmp( $tmp_base );
146
- } else {
147
- $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
148
- WPO_WCPDF()->main->copy_fonts( $font_path );
149
- }
150
-
151
- // 1.5.28 update: copy next invoice number to separate setting
152
- if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
153
- $template_settings = get_option( 'wpo_wcpdf_template_settings' );
154
- $next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
155
- update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
156
- }
157
-
158
- // 2.0-dev update: reorganize settings
159
- if ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) ) {
160
- $old_settings = array(
161
- 'wpo_wcpdf_general_settings' => get_option( 'wpo_wcpdf_general_settings' ),
162
- 'wpo_wcpdf_template_settings' => get_option( 'wpo_wcpdf_template_settings' ),
163
- 'wpo_wcpdf_debug_settings' => get_option( 'wpo_wcpdf_debug_settings' ),
164
- );
165
-
166
- // combine invoice number formatting in array
167
- $old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'] = array();
168
- $format_option_keys = array('padding','suffix','prefix');
169
- foreach ($format_option_keys as $format_option_key) {
170
- if (isset($old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"])) {
171
- $old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'][$format_option_key] = $old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"];
172
- }
173
- }
174
-
175
- // convert abbreviated email_ids
176
- if (isset($old_settings['wpo_wcpdf_general_settings']['email_pdf'])) {
177
- foreach ($old_settings['wpo_wcpdf_general_settings']['email_pdf'] as $email_id => $value) {
178
- if ($email_id == 'completed' || $email_id == 'processing') {
179
- $old_settings['wpo_wcpdf_general_settings']['email_pdf']["customer_{$email_id}_order"] = $value;
180
- unset($old_settings['wpo_wcpdf_general_settings']['email_pdf'][$email_id]);
181
- }
182
- }
183
- }
184
-
185
- // Migrate template path
186
- // forward slash for consistency/compatibility
187
- $template_path = str_replace('\\','/', $old_settings['wpo_wcpdf_template_settings']['template_path']);
188
- // strip abspath (forward slashed) if included
189
- $template_path = str_replace( str_replace('\\','/', ABSPATH), '', $template_path );
190
- // strip pdf subfolder from templates path
191
- $template_path = str_replace( '/templates/pdf/', '/templates/', $template_path );
192
- $old_settings['wpo_wcpdf_template_settings']['template_path'] = $template_path;
193
-
194
- // map new settings to old
195
- $settings_map = array(
196
- 'wpo_wcpdf_settings_general' => array(
197
- 'download_display' => array( 'wpo_wcpdf_general_settings' => 'download_display' ),
198
- 'template_path' => array( 'wpo_wcpdf_template_settings' => 'template_path' ),
199
- 'currency_font' => array( 'wpo_wcpdf_template_settings' => 'currency_font' ),
200
- 'paper_size' => array( 'wpo_wcpdf_template_settings' => 'paper_size' ),
201
- 'header_logo' => array( 'wpo_wcpdf_template_settings' => 'header_logo' ),
202
- 'shop_name' => array( 'wpo_wcpdf_template_settings' => 'shop_name' ),
203
- 'shop_address' => array( 'wpo_wcpdf_template_settings' => 'shop_address' ),
204
- 'footer' => array( 'wpo_wcpdf_template_settings' => 'footer' ),
205
- 'extra_1' => array( 'wpo_wcpdf_template_settings' => 'extra_1' ),
206
- 'extra_2' => array( 'wpo_wcpdf_template_settings' => 'extra_2' ),
207
- 'extra_3' => array( 'wpo_wcpdf_template_settings' => 'extra_3' ),
208
- ),
209
- 'wpo_wcpdf_documents_settings_invoice' => array(
210
- 'attach_to_email_ids' => array( 'wpo_wcpdf_general_settings' => 'email_pdf' ),
211
- 'display_shipping_address' => array( 'wpo_wcpdf_template_settings' => 'invoice_shipping_address' ),
212
- 'display_email' => array( 'wpo_wcpdf_template_settings' => 'invoice_email' ),
213
- 'display_phone' => array( 'wpo_wcpdf_template_settings' => 'invoice_phone' ),
214
- 'display_date' => array( 'wpo_wcpdf_template_settings' => 'display_date' ),
215
- 'display_number' => array( 'wpo_wcpdf_template_settings' => 'display_number' ),
216
- 'number_format' => array( 'wpo_wcpdf_template_settings' => 'invoice_number_formatting' ),
217
- 'reset_number_yearly' => array( 'wpo_wcpdf_template_settings' => 'yearly_reset_invoice_number' ),
218
- 'my_account_buttons' => array( 'wpo_wcpdf_general_settings' => 'my_account_buttons' ),
219
- 'invoice_number_column' => array( 'wpo_wcpdf_general_settings' => 'invoice_number_column' ),
220
- 'disable_free' => array( 'wpo_wcpdf_general_settings' => 'disable_free' ),
221
- ),
222
- 'wpo_wcpdf_documents_settings_packing-slip' => array(
223
- 'display_billing_address' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_billing_address' ),
224
- 'display_email' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_email' ),
225
- 'display_phone' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_phone' ),
226
- ),
227
- 'wpo_wcpdf_settings_debug' => array(
228
- 'enable_debug' => array( 'wpo_wcpdf_debug_settings' => 'enable_debug' ),
229
- 'html_output' => array( 'wpo_wcpdf_debug_settings' => 'html_output' ),
230
- ),
231
- );
232
-
233
- // walk through map
234
- foreach ($settings_map as $new_option => $new_settings_keys) {
235
- ${$new_option} = array();
236
- foreach ($new_settings_keys as $new_key => $old_setting ) {
237
- $old_key = reset($old_setting);
238
- $old_option = key($old_setting);
239
- if (!empty($old_settings[$old_option][$old_key])) {
240
- // turn translatable fields into array
241
- $translatable_fields = array('shop_name','shop_address','footer','extra_1','extra_2','extra_3');
242
- if (in_array($new_key, $translatable_fields)) {
243
- ${$new_option}[$new_key] = array( 'default' => $old_settings[$old_option][$old_key] );
244
- } else {
245
- ${$new_option}[$new_key] = $old_settings[$old_option][$old_key];
246
- }
247
- }
248
- }
249
-
250
- // auto enable invoice & packing slip
251
- $enabled = array( 'wpo_wcpdf_documents_settings_invoice', 'wpo_wcpdf_documents_settings_packing-slip' );
252
- if ( in_array( $new_option, $enabled ) ) {
253
- ${$new_option}['enabled'] = 1;
254
- }
255
-
256
- // auto enable legacy mode
257
- if ( $new_option == 'wpo_wcpdf_settings_debug' ) {
258
- ${$new_option}['legacy_mode'] = 1;
259
- }
260
-
261
- // merge with existing settings
262
- ${$new_option."_old"} = get_option( $new_option, ${$new_option} ); // second argument loads new as default in case the settings did not exist yet
263
- ${$new_option} = (array) ${$new_option} + (array) ${$new_option."_old"}; // duplicate options take new options as default
264
-
265
- // store new option values
266
- update_option( $new_option, ${$new_option} );
267
- }
268
- }
269
-
270
- // 2.0-beta-2 update: copy next number to separate db store
271
- if ( version_compare( $installed_version, '2.0-beta-2', '<' ) ) {
272
- // load number store class (just in case)
273
- include_once( WPO_WCPDF()->plugin_path() . '/includes/documents/class-wcpdf-sequential-number-store.php' );
274
-
275
- $next_number = get_option( 'wpo_wcpdf_next_invoice_number' );
276
- if (!empty($next_number)) {
277
- $number_store = new \WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store( 'invoice_number' );
278
- $number_store->set_next( (int) $next_number );
279
- }
280
- // we're not deleting this option yet to make downgrading possible
281
- // delete_option( 'wpo_wcpdf_next_invoice_number' ); // clean up after ourselves
282
- }
283
-
284
- }
285
-
286
- /**
287
- * Plugin downgrade method. Perform any required downgrades here
288
- *
289
- *
290
- * @param string $installed_version the currently installed ('old') version (actually higher since this is a downgrade)
291
- */
292
- protected function downgrade( $installed_version ) {
293
- // make sure fonts match with version: copy from plugin folder
294
- $tmp_base = WPO_WCPDF()->main->get_tmp_base();
295
-
296
- // check if tmp folder exists => if not, initialize
297
- if ( !@is_dir( $tmp_base ) ) {
298
- WPO_WCPDF()->main->init_tmp( $tmp_base );
299
- } else {
300
- $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
301
- WPO_WCPDF()->main->copy_fonts( $font_path );
302
- }
303
- }
304
-
305
- }
306
-
307
- endif; // class_exists
308
-
 
 
 
309
  return new Install();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly
10
+ }
11
+
12
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Install' ) ) :
13
+
14
+ class Install {
15
+
16
+ function __construct() {
17
+ // run lifecycle methods
18
+ if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
19
+ add_action( 'wp_loaded', array( $this, 'do_install' ) );
20
+ }
21
+ }
22
+
23
+ /** Lifecycle methods *******************************************************
24
+ * Because register_activation_hook only runs when the plugin is manually
25
+ * activated by the user, we're checking the current version against the
26
+ * version stored in the database
27
+ ****************************************************************************/
28
+
29
+ /**
30
+ * Handles version checking
31
+ */
32
+ public function do_install() {
33
+ // only install when woocommerce is active
34
+ if ( !WPO_WCPDF()->is_woocommerce_activated() ) {
35
+ return;
36
+ }
37
+
38
+ $version_setting = 'wpo_wcpdf_version';
39
+ $installed_version = get_option( $version_setting );
40
+
41
+ // installed version lower than plugin version?
42
+ if ( version_compare( $installed_version, WPO_WCPDF_VERSION, '<' ) ) {
43
+
44
+ if ( ! $installed_version ) {
45
+ $this->install();
46
+ } else {
47
+ $this->upgrade( $installed_version );
48
+ }
49
+
50
+ // new version number
51
+ update_option( $version_setting, WPO_WCPDF_VERSION );
52
+ } elseif ( $installed_version && version_compare( $installed_version, WPO_WCPDF_VERSION, '>' ) ) {
53
+ $this->downgrade( $installed_version );
54
+ // downgrade version number
55
+ update_option( $version_setting, WPO_WCPDF_VERSION );
56
+ }
57
+ }
58
+
59
+
60
+ /**
61
+ * Plugin install method. Perform any installation tasks here
62
+ */
63
+ protected function install() {
64
+ // only install when php 5.3 or higher
65
+ if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
66
+ return;
67
+ }
68
+
69
+ // check if upgrading from versionless (1.4.14 and older)
70
+ if ( get_option('wpo_wcpdf_general_settings') ) {
71
+ $this->upgrade( 'versionless' );
72
+ return;
73
+ }
74
+
75
+ // Create temp folders
76
+ $tmp_base = WPO_WCPDF()->main->get_tmp_base();
77
+
78
+ // check if tmp folder exists => if not, initialize
79
+ if ( !@is_dir( $tmp_base ) ) {
80
+ WPO_WCPDF()->main->init_tmp( $tmp_base );
81
+ }
82
+
83
+ // set default settings
84
+ $settings_defaults = array(
85
+ 'wpo_wcpdf_settings_general' => array(
86
+ 'download_display' => 'display',
87
+ 'template_path' => WPO_WCPDF()->plugin_path() . '/templates/Simple',
88
+ // 'currency_font' => '',
89
+ 'paper_size' => 'a4',
90
+ // 'header_logo' => '',
91
+ // 'shop_name' => array(),
92
+ // 'shop_address' => array(),
93
+ // 'footer' => array(),
94
+ // 'extra_1' => array(),
95
+ // 'extra_2' => array(),
96
+ // 'extra_3' => array(),
97
+ ),
98
+ 'wpo_wcpdf_documents_settings_invoice' => array(
99
+ 'enabled' => 1,
100
+ // 'attach_to_email_ids' => array(),
101
+ // 'display_shipping_address' => '',
102
+ // 'display_email' => '',
103
+ // 'display_phone' => '',
104
+ // 'display_date' => '',
105
+ // 'display_number' => '',
106
+ // 'number_format' => array(),
107
+ // 'reset_number_yearly' => '',
108
+ // 'my_account_buttons' => '',
109
+ // 'invoice_number_column' => '',
110
+ // 'disable_free' => '',
111
+ ),
112
+ 'wpo_wcpdf_documents_settings_packing-slip' => array(
113
+ 'enabled' => 1,
114
+ // 'display_billing_address' => '',
115
+ // 'display_email' => '',
116
+ // 'display_phone' => '',
117
+ ),
118
+ // 'wpo_wcpdf_settings_debug' => array(
119
+ // 'legacy_mode' => '',
120
+ // 'enable_debug' => '',
121
+ // 'html_output' => '',
122
+ // ),
123
+ );
124
+ foreach ($settings_defaults as $option => $defaults) {
125
+ update_option( $option, $defaults );
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Plugin upgrade method. Perform any required upgrades here
131
+ *
132
+ * @param string $installed_version the currently installed ('old') version
133
+ */
134
+ protected function upgrade( $installed_version ) {
135
+ // only upgrade when php 5.3 or higher
136
+ if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
137
+ return;
138
+ }
139
+
140
+ // sync fonts on every upgrade!
141
+ $tmp_base = WPO_WCPDF()->main->get_tmp_base();
142
+
143
+ // check if tmp folder exists => if not, initialize
144
+ if ( !@is_dir( $tmp_base ) ) {
145
+ WPO_WCPDF()->main->init_tmp( $tmp_base );
146
+ } else {
147
+ $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
148
+ // don't try merging fonts with local when updating pre 2.0
149
+ $pre_2 = ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) );
150
+ $merge_with_local = $pre_2 ? false : true;
151
+ WPO_WCPDF()->main->copy_fonts( $font_path, $merge_with_local );
152
+ }
153
+
154
+ // 1.5.28 update: copy next invoice number to separate setting
155
+ if ( $installed_version == 'versionless' || version_compare( $installed_version, '1.5.28', '<' ) ) {
156
+ $template_settings = get_option( 'wpo_wcpdf_template_settings' );
157
+ $next_invoice_number = isset($template_settings['next_invoice_number'])?$template_settings['next_invoice_number']:'';
158
+ update_option( 'wpo_wcpdf_next_invoice_number', $next_invoice_number );
159
+ }
160
+
161
+ // 2.0-dev update: reorganize settings
162
+ if ( $installed_version == 'versionless' || version_compare( $installed_version, '2.0-dev', '<' ) ) {
163
+ $old_settings = array(
164
+ 'wpo_wcpdf_general_settings' => get_option( 'wpo_wcpdf_general_settings' ),
165
+ 'wpo_wcpdf_template_settings' => get_option( 'wpo_wcpdf_template_settings' ),
166
+ 'wpo_wcpdf_debug_settings' => get_option( 'wpo_wcpdf_debug_settings' ),
167
+ );
168
+
169
+ // combine invoice number formatting in array
170
+ $old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'] = array();
171
+ $format_option_keys = array('padding','suffix','prefix');
172
+ foreach ($format_option_keys as $format_option_key) {
173
+ if (isset($old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"])) {
174
+ $old_settings['wpo_wcpdf_template_settings']['invoice_number_formatting'][$format_option_key] = $old_settings['wpo_wcpdf_template_settings']["invoice_number_formatting_{$format_option_key}"];
175
+ }
176
+ }
177
+
178
+ // convert abbreviated email_ids
179
+ if (isset($old_settings['wpo_wcpdf_general_settings']['email_pdf'])) {
180
+ foreach ($old_settings['wpo_wcpdf_general_settings']['email_pdf'] as $email_id => $value) {
181
+ if ($email_id == 'completed' || $email_id == 'processing') {
182
+ $old_settings['wpo_wcpdf_general_settings']['email_pdf']["customer_{$email_id}_order"] = $value;
183
+ unset($old_settings['wpo_wcpdf_general_settings']['email_pdf'][$email_id]);
184
+ }
185
+ }
186
+ }
187
+
188
+ // Migrate template path
189
+ // forward slash for consistency/compatibility
190
+ $template_path = str_replace('\\','/', $old_settings['wpo_wcpdf_template_settings']['template_path']);
191
+ // strip abspath (forward slashed) if included
192
+ $template_path = str_replace( str_replace('\\','/', ABSPATH), '', $template_path );
193
+ // strip pdf subfolder from templates path
194
+ $template_path = str_replace( '/templates/pdf/', '/templates/', $template_path );
195
+ $old_settings['wpo_wcpdf_template_settings']['template_path'] = $template_path;
196
+
197
+ // map new settings to old
198
+ $settings_map = array(
199
+ 'wpo_wcpdf_settings_general' => array(
200
+ 'download_display' => array( 'wpo_wcpdf_general_settings' => 'download_display' ),
201
+ 'template_path' => array( 'wpo_wcpdf_template_settings' => 'template_path' ),
202
+ 'currency_font' => array( 'wpo_wcpdf_template_settings' => 'currency_font' ),
203
+ 'paper_size' => array( 'wpo_wcpdf_template_settings' => 'paper_size' ),
204
+ 'header_logo' => array( 'wpo_wcpdf_template_settings' => 'header_logo' ),
205
+ 'shop_name' => array( 'wpo_wcpdf_template_settings' => 'shop_name' ),
206
+ 'shop_address' => array( 'wpo_wcpdf_template_settings' => 'shop_address' ),
207
+ 'footer' => array( 'wpo_wcpdf_template_settings' => 'footer' ),
208
+ 'extra_1' => array( 'wpo_wcpdf_template_settings' => 'extra_1' ),
209
+ 'extra_2' => array( 'wpo_wcpdf_template_settings' => 'extra_2' ),
210
+ 'extra_3' => array( 'wpo_wcpdf_template_settings' => 'extra_3' ),
211
+ ),
212
+ 'wpo_wcpdf_documents_settings_invoice' => array(
213
+ 'attach_to_email_ids' => array( 'wpo_wcpdf_general_settings' => 'email_pdf' ),
214
+ 'display_shipping_address' => array( 'wpo_wcpdf_template_settings' => 'invoice_shipping_address' ),
215
+ 'display_email' => array( 'wpo_wcpdf_template_settings' => 'invoice_email' ),
216
+ 'display_phone' => array( 'wpo_wcpdf_template_settings' => 'invoice_phone' ),
217
+ 'display_date' => array( 'wpo_wcpdf_template_settings' => 'display_date' ),
218
+ 'display_number' => array( 'wpo_wcpdf_template_settings' => 'display_number' ),
219
+ 'number_format' => array( 'wpo_wcpdf_template_settings' => 'invoice_number_formatting' ),
220
+ 'reset_number_yearly' => array( 'wpo_wcpdf_template_settings' => 'yearly_reset_invoice_number' ),
221
+ 'my_account_buttons' => array( 'wpo_wcpdf_general_settings' => 'my_account_buttons' ),
222
+ 'invoice_number_column' => array( 'wpo_wcpdf_general_settings' => 'invoice_number_column' ),
223
+ 'disable_free' => array( 'wpo_wcpdf_general_settings' => 'disable_free' ),
224
+ ),
225
+ 'wpo_wcpdf_documents_settings_packing-slip' => array(
226
+ 'display_billing_address' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_billing_address' ),
227
+ 'display_email' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_email' ),
228
+ 'display_phone' => array( 'wpo_wcpdf_template_settings' => 'packing_slip_phone' ),
229
+ ),
230
+ 'wpo_wcpdf_settings_debug' => array(
231
+ 'enable_debug' => array( 'wpo_wcpdf_debug_settings' => 'enable_debug' ),
232
+ 'html_output' => array( 'wpo_wcpdf_debug_settings' => 'html_output' ),
233
+ ),
234
+ );
235
+
236
+ // walk through map
237
+ foreach ($settings_map as $new_option => $new_settings_keys) {
238
+ ${$new_option} = array();
239
+ foreach ($new_settings_keys as $new_key => $old_setting ) {
240
+ $old_key = reset($old_setting);
241
+ $old_option = key($old_setting);
242
+ if (!empty($old_settings[$old_option][$old_key])) {
243
+ // turn translatable fields into array
244
+ $translatable_fields = array('shop_name','shop_address','footer','extra_1','extra_2','extra_3');
245
+ if (in_array($new_key, $translatable_fields)) {
246
+ ${$new_option}[$new_key] = array( 'default' => $old_settings[$old_option][$old_key] );
247
+ } else {
248
+ ${$new_option}[$new_key] = $old_settings[$old_option][$old_key];
249
+ }
250
+ }
251
+ }
252
+
253
+ // auto enable invoice & packing slip
254
+ $enabled = array( 'wpo_wcpdf_documents_settings_invoice', 'wpo_wcpdf_documents_settings_packing-slip' );
255
+ if ( in_array( $new_option, $enabled ) ) {
256
+ ${$new_option}['enabled'] = 1;
257
+ }
258
+
259
+ // auto enable legacy mode
260
+ if ( $new_option == 'wpo_wcpdf_settings_debug' ) {
261
+ ${$new_option}['legacy_mode'] = 1;
262
+ }
263
+
264
+ // merge with existing settings
265
+ ${$new_option."_old"} = get_option( $new_option, ${$new_option} ); // second argument loads new as default in case the settings did not exist yet
266
+ ${$new_option} = (array) ${$new_option} + (array) ${$new_option."_old"}; // duplicate options take new options as default
267
+
268
+ // store new option values
269
+ update_option( $new_option, ${$new_option} );
270
+ }
271
+ }
272
+
273
+ // 2.0-beta-2 update: copy next number to separate db store
274
+ if ( version_compare( $installed_version, '2.0-beta-2', '<' ) ) {
275
+ // load number store class (just in case)
276
+ include_once( WPO_WCPDF()->plugin_path() . '/includes/documents/class-wcpdf-sequential-number-store.php' );
277
+
278
+ $next_number = get_option( 'wpo_wcpdf_next_invoice_number' );
279
+ if (!empty($next_number)) {
280
+ $number_store = new \WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store( 'invoice_number' );
281
+ $number_store->set_next( (int) $next_number );
282
+ }
283
+ // we're not deleting this option yet to make downgrading possible
284
+ // delete_option( 'wpo_wcpdf_next_invoice_number' ); // clean up after ourselves
285
+ }
286
+
287
+ }
288
+
289
+ /**
290
+ * Plugin downgrade method. Perform any required downgrades here
291
+ *
292
+ *
293
+ * @param string $installed_version the currently installed ('old') version (actually higher since this is a downgrade)
294
+ */
295
+ protected function downgrade( $installed_version ) {
296
+ // make sure fonts match with version: copy from plugin folder
297
+ $tmp_base = WPO_WCPDF()->main->get_tmp_base();
298
+
299
+ // check if tmp folder exists => if not, initialize
300
+ if ( !@is_dir( $tmp_base ) ) {
301
+ WPO_WCPDF()->main->init_tmp( $tmp_base );
302
+ } else {
303
+ $font_path = WPO_WCPDF()->main->get_tmp_path( 'fonts' );
304
+ WPO_WCPDF()->main->copy_fonts( $font_path );
305
+ }
306
+ }
307
+
308
+ }
309
+
310
+ endif; // class_exists
311
+
312
  return new Install();
includes/class-wcpdf-main.php CHANGED
@@ -1,465 +1,502 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly
10
- }
11
-
12
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Main' ) ) :
13
-
14
- class Main {
15
-
16
- function __construct() {
17
- add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
18
- add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3 );
19
- add_filter( 'wpo_wcpdf_custom_attachment_condition', array( $this, 'disable_free_attachment'), 10, 4 );
20
-
21
- if ( isset(WPO_WCPDF()->settings->debug_settings['enable_debug']) ) {
22
- $this->enable_debug();
23
- }
24
- if ( isset(WPO_WCPDF()->settings->debug_settings['html_output']) ) {
25
- add_filter( 'wpo_wcpdf_use_path', '__return_false' );
26
- }
27
-
28
- // include template specific custom functions
29
- $template_path = WPO_WCPDF()->settings->get_template_path();
30
- if ( file_exists( $template_path . '/template-functions.php' ) ) {
31
- require_once( $template_path . '/template-functions.php' );
32
- }
33
-
34
- // page numbers & currency filters
35
- add_action( 'wpo_wcpdf_get_html', array($this, 'format_page_number_placeholders' ), 10, 2 );
36
- add_action( 'wpo_wcpdf_after_dompdf_render', array($this, 'page_number_replacements' ), 9, 2 );
37
- if ( isset( WPO_WCPDF()->settings->general_settings['currency_font'] ) ) {
38
- add_action( 'wpo_wcpdf_before_pdf', array($this, 'use_currency_font' ), 10, 2 );
39
- }
40
-
41
- // scheduled attachments cleanup - disabled for now
42
- // add_action( 'wp_scheduled_delete', array( $this, 'attachments_cleanup') );
43
- }
44
-
45
- /**
46
- * Attach PDF to WooCommerce email
47
- */
48
- public function attach_pdf_to_email ( $attachments, $email_id, $order ) {
49
- // check if all variables properly set
50
- if ( !is_object( $order ) || !isset( $email_id ) ) {
51
- return $attachments;
52
- }
53
-
54
- // Skip User emails
55
- if ( get_class( $order ) == 'WP_User' ) {
56
- return $attachments;
57
- }
58
-
59
- $order_id = WCX_Order::get_id( $order );
60
-
61
- if ( get_class( $order ) !== 'WC_Order' && $order_id == false ) {
62
- return $attachments;
63
- }
64
-
65
- // WooCommerce Booking compatibility
66
- if ( get_post_type( $order_id ) == 'wc_booking' && isset($order->order) ) {
67
- // $order is actually a WC_Booking object!
68
- $order = $order->order;
69
- }
70
-
71
- // do not process low stock notifications, user emails etc!
72
- if ( in_array( $email_id, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order_id ) != 'shop_order' ) {
73
- return $attachments;
74
- }
75
-
76
- $tmp_path = $this->get_tmp_path('attachments');
77
-
78
- // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
79
- // array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
80
-
81
- // disable deprecation notices during email sending
82
- add_filter( 'wcpdf_disable_deprecation_notices', '__return_true' );
83
-
84
- $attach_to_document_types = $this->get_documents_for_email( $email_id, $order );
85
- foreach ( $attach_to_document_types as $document_type ) {
86
- do_action( 'wpo_wcpdf_before_attachment_creation', $order, $email_id, $document_type );
87
-
88
- try {
89
- // prepare document
90
- $document = wcpdf_get_document( $document_type, (array) $order_id, true );
91
- if ( !$document ) { // something went wrong, continue trying with other documents
92
- continue;
93
- }
94
-
95
- // get pdf data & store
96
- $pdf_data = $document->get_pdf();
97
- $filename = $document->get_filename();
98
- $pdf_path = $tmp_path . $filename;
99
- file_put_contents ( $pdf_path, $pdf_data );
100
- $attachments[] = $pdf_path;
101
-
102
- do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $document_type );
103
- } catch (Exception $e) {
104
- error_log($e->getMessage());
105
- continue;
106
- }
107
- }
108
-
109
- remove_filter( 'wcpdf_disable_deprecation_notices', '__return_true' );
110
-
111
- return $attachments;
112
- }
113
-
114
- public function get_documents_for_email( $email_id, $order ) {
115
- $documents = WPO_WCPDF()->documents->get_documents();
116
-
117
- $attach_documents = array();
118
- foreach ($documents as $document) {
119
- $attach_documents[ $document->get_type() ] = $document->get_attach_to_email_ids();
120
- }
121
- $attach_documents = apply_filters('wpo_wcpdf_attach_documents', $attach_documents );
122
-
123
- $document_types = array();
124
- foreach ($attach_documents as $document_type => $attach_to_email_ids ) {
125
- // legacy settings: convert abbreviated email_ids
126
- foreach ($attach_to_email_ids as $key => $attach_to_email_id) {
127
- if ($attach_to_email_id == 'completed' || $attach_to_email_id == 'processing') {
128
- $attach_to_email_ids[$key] = "customer_" . $attach_to_email_id . "_order";
129
- }
130
- }
131
-
132
- $extra_condition = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $email_id, $document_type );
133
- if ( in_array( $email_id, $attach_to_email_ids ) && $extra_condition === true ) {
134
- $document_types[] = $document_type;
135
- }
136
- }
137
-
138
- return $document_types;
139
- }
140
-
141
- /**
142
- * Load and generate the template output with ajax
143
- */
144
- public function generate_pdf_ajax() {
145
- // Check the nonce
146
- if( empty( $_GET['action'] ) || !check_admin_referer( $_GET['action'] ) ) {
147
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ) );
148
- }
149
-
150
- // Check if all parameters are set
151
- if ( empty( $_GET['document_type'] ) && !empty( $_GET['template_type'] ) ) {
152
- $_GET['document_type'] = $_GET['template_type'];
153
- }
154
-
155
- if ( empty( $_GET['order_ids'] ) ) {
156
- wp_die( __( "You haven't selected any orders", 'woocommerce-pdf-invoices-packing-slips' ) );
157
- }
158
-
159
- if( empty( $_GET['document_type'] ) ) {
160
- wp_die( __( 'Some of the export parameters are missing.', 'woocommerce-pdf-invoices-packing-slips' ) );
161
- }
162
-
163
- // Generate the output
164
- $document_type = $_GET['document_type'];
165
-
166
- $order_ids = (array) explode('x',$_GET['order_ids']);
167
- // Process oldest first: reverse $order_ids array
168
- $order_ids = array_reverse($order_ids);
169
-
170
- // set default is allowed
171
- $allowed = true;
172
-
173
- // check if user is logged in
174
- if ( ! is_user_logged_in() ) {
175
- $allowed = false;
176
- }
177
-
178
- // Check the user privileges
179
- if( !( current_user_can( 'manage_woocommerce_orders' ) || current_user_can( 'edit_shop_orders' ) ) && !isset( $_GET['my-account'] ) ) {
180
- $allowed = false;
181
- }
182
-
183
- // User call from my-account page
184
- if ( !current_user_can('manage_options') && isset( $_GET['my-account'] ) ) {
185
- // Only for single orders!
186
- if ( count( $order_ids ) > 1 ) {
187
- $allowed = false;
188
- }
189
-
190
- // Check if current user is owner of order IMPORTANT!!!
191
- if ( ! current_user_can( 'view_order', $order_ids[0] ) ) {
192
- $allowed = false;
193
- }
194
- }
195
-
196
- $allowed = apply_filters( 'wpo_wcpdf_check_privs', $allowed, $order_ids );
197
-
198
- if ( ! $allowed ) {
199
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ) );
200
- }
201
-
202
- // if we got here, we're safe to go!
203
- try {
204
- $document = wcpdf_get_document( $document_type, $order_ids, true );
205
-
206
- if ( $document ) {
207
- $output_format = WPO_WCPDF()->settings->get_output_format( $document_type );
208
- switch ( $output_format ) {
209
- case 'html':
210
- $document->output_html();
211
- break;
212
- case 'pdf':
213
- default:
214
- if ( has_action( 'wpo_wcpdf_created_manually' ) ) {
215
- do_action( 'wpo_wcpdf_created_manually', $document->get_pdf(), $document->get_filename() );
216
- }
217
- $output_mode = WPO_WCPDF()->settings->get_output_mode( $document_type );
218
- $document->output_pdf( $output_mode );
219
- break;
220
- }
221
- } else {
222
- wp_die( sprintf( __( "Document of type '%s' for the selected order(s) could not be generated", 'woocommerce-pdf-invoices-packing-slips' ), $document_type ) );
223
- }
224
- } catch (Exception $e) {
225
- echo $e->getMessage();
226
- }
227
-
228
- exit;
229
- }
230
-
231
- /**
232
- * Return tmp path for different plugin processes
233
- */
234
- public function get_tmp_path ( $type = '' ) {
235
- $tmp_base = $this->get_tmp_base();
236
- // check if tmp folder exists => if not, initialize
237
- if ( !@is_dir( $tmp_base ) ) {
238
- $this->init_tmp( $tmp_base );
239
- }
240
-
241
- if ( empty( $type ) ) {
242
- return $tmp_base;
243
- }
244
-
245
- switch ( $type ) {
246
- case 'dompdf':
247
- $tmp_path = $tmp_base . 'dompdf';
248
- break;
249
- case 'font_cache':
250
- case 'fonts':
251
- $tmp_path = $tmp_base . 'fonts';
252
- break;
253
- case 'attachments':
254
- $tmp_path = $tmp_base . 'attachments/';
255
- break;
256
- default:
257
- $tmp_path = $tmp_base . $type;
258
- break;
259
- }
260
-
261
- // double check for existence, in case tmp_base was installed, but subfolder not created
262
- if ( !@is_dir( $tmp_path ) ) {
263
- @mkdir( $tmp_path );
264
- }
265
-
266
- return $tmp_path;
267
- }
268
-
269
- /**
270
- * return the base tmp folder (usually uploads)
271
- */
272
- public function get_tmp_base () {
273
- // wp_upload_dir() is used to set the base temp folder, under which a
274
- // 'wpo_wcpdf' folder and several subfolders are created
275
- //
276
- // wp_upload_dir() will:
277
- // * default to WP_CONTENT_DIR/uploads
278
- // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
279
- //
280
- // May also be overridden by the wpo_wcpdf_tmp_path filter
281
-
282
- $upload_dir = wp_upload_dir();
283
- $upload_base = trailingslashit( $upload_dir['basedir'] );
284
- $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
285
- return $tmp_base;
286
- }
287
-
288
- /**
289
- * Install/create plugin tmp folders
290
- */
291
- public function init_tmp ( $tmp_base ) {
292
- // create plugin base temp folder
293
- @mkdir( $tmp_base );
294
-
295
- // create subfolders & protect
296
- $subfolders = array( 'attachments', 'fonts', 'dompdf' );
297
- foreach ( $subfolders as $subfolder ) {
298
- $path = $tmp_base . $subfolder . '/';
299
- @mkdir( $path );
300
-
301
- // copy font files
302
- if ( $subfolder == 'fonts' ) {
303
- $this->copy_fonts( $path );
304
- }
305
-
306
- // create .htaccess file and empty index.php to protect in case an open webfolder is used!
307
- @file_put_contents( $path . '.htaccess', 'deny from all' );
308
- @touch( $path . 'index.php' );
309
- }
310
-
311
- }
312
-
313
- /**
314
- * Copy DOMPDF fonts to wordpress tmp folder
315
- */
316
- public function copy_fonts ( $path ) {
317
- $path = trailingslashit( $path );
318
- $dompdf_font_dir = WPO_WCPDF()->plugin_path() . "/vendor/dompdf/dompdf/lib/fonts/";
319
-
320
- // first try the easy way with glob!
321
- if ( function_exists('glob') ) {
322
- $files = glob($dompdf_font_dir."*.*");
323
- foreach($files as $file){
324
- if(!is_dir($file) && is_readable($file)) {
325
- $dest = $path . basename($file);
326
- copy($file, $dest);
327
- }
328
- }
329
- } else {
330
- // fallback method using font cache file (glob is disabled on some servers with disable_functions)
331
- $font_cache_file = $dompdf_font_dir . "dompdf_font_family_cache.php";
332
- $font_cache_dist_file = $dompdf_font_dir . "dompdf_font_family_cache.dist.php";
333
- $fonts = @require_once( $font_cache_file );
334
- $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm' );
335
-
336
- foreach ($fonts as $font_family => $filenames) {
337
- foreach ($filenames as $filename) {
338
- foreach ($extensions as $extension) {
339
- $file = $filename.$extension;
340
- if (file_exists($file)) {
341
- $dest = $path . basename($file);
342
- copy($file, $dest);
343
- }
344
- }
345
- }
346
- }
347
-
348
- // copy cache files separately
349
- copy($font_cache_file, $path.basename($font_cache_file));
350
- copy($font_cache_dist_file, $path.basename($font_cache_dist_file));
351
- }
352
- }
353
-
354
- public function disable_free_attachment( $attach, $order, $email_id, $document_type ) {
355
- // prevent fatal error for non-order objects
356
- if ( !method_exists( $order, 'get_total' ) ) {
357
- return false;
358
- }
359
-
360
- $document_settings = WPO_WCPDF()->settings->get_document_settings( $document_type );
361
- // echo '<pre>';var_dump($document_type);echo '</pre>';
362
- // error_log( var_export($document_settings,true) );
363
-
364
- // check order total & setting
365
- $order_total = $order->get_total();
366
- if ( $order_total == 0 && isset( $document_settings['disable_free'] ) ) {
367
- return false;
368
- }
369
-
370
- return $attach;
371
- }
372
-
373
- /**
374
- * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
375
- */
376
- public function format_page_number_placeholders ( $html, $document ) {
377
- $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">^C^</span>', $html);
378
- $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
379
- return $html;
380
- }
381
-
382
- /**
383
- * Replace {{PAGE_COUNT}} placeholder with total page count
384
- */
385
- public function page_number_replacements ( $dompdf, $html ) {
386
- $placeholder = '^C^';
387
- // create placeholder version with ASCII 0 spaces (dompdf 0.8)
388
- $placeholder_0 = '';
389
- $placeholder_chars = str_split($placeholder);
390
- foreach ($placeholder_chars as $placeholder_char) {
391
- $placeholder_0 .= chr(0).$placeholder_char;
392
- }
393
-
394
- // check if placeholder is used
395
- if (strpos($html, $placeholder) !== false ) {
396
- foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
397
- if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false ) {
398
- $object["c"] = str_replace( array($placeholder,$placeholder_0) , $dompdf->get_canvas()->get_page_count() , $object["c"] );
399
- } elseif (array_key_exists("c", $object) && strpos($object["c"], $placeholder_0) !== false ) {
400
- $object["c"] = str_replace( array($placeholder,$placeholder_0) , chr(0).$dompdf->get_canvas()->get_page_count() , $object["c"] );
401
- }
402
- }
403
- }
404
-
405
- return $dompdf;
406
- }
407
-
408
- /**
409
- * Use currency symbol font (when enabled in options)
410
- */
411
- public function use_currency_font ( $document_type, $document ) {
412
- add_filter( 'woocommerce_currency_symbol', array( $this, 'wrap_currency_symbol' ), 10, 2);
413
- add_action( 'wpo_wcpdf_custom_styles', array($this, 'currency_symbol_font_styles' ) );
414
- }
415
-
416
- public function wrap_currency_symbol( $currency_symbol, $currency ) {
417
- $currency_symbol = sprintf( '<span class="wcpdf-currency-symbol">%s</span>', $currency_symbol );
418
- return $currency_symbol;
419
- }
420
-
421
- public function currency_symbol_font_styles () {
422
- ?>
423
- .wcpdf-currency-symbol { font-family: 'Currencies'; }
424
- <?php
425
- }
426
-
427
- /**
428
- * Remove attachments older than 1 week (daily, hooked into wp_scheduled_delete )
429
- */
430
- public function attachments_cleanup() {
431
- if ( !function_exists("glob") || !function_exists('filemtime')) {
432
- // glob is disabled
433
- return;
434
- }
435
-
436
- $delete_timestamp = time() - ( DAY_IN_SECONDS * 7 );
437
-
438
- $tmp_path = WPO_WCPDF()->main->get_tmp_path('attachments');
439
-
440
- if ( $files = glob( $tmp_path.'*.pdf' ) ) { // get all pdf files
441
- foreach( $files as $file ) {
442
- if( is_file( $file ) ) {
443
- $file_timestamp = filemtime( $file );
444
- if ( !empty( $file_timestamp ) && $file_timestamp < $delete_timestamp ) {
445
- @unlink($file);
446
- }
447
- }
448
- }
449
- }
450
-
451
- }
452
-
453
- /**
454
- * Enable PHP error output
455
- */
456
- public function enable_debug () {
457
- error_reporting( E_ALL );
458
- ini_set( 'display_errors', 1 );
459
- }
460
-
461
- }
462
-
463
- endif; // class_exists
464
-
465
- return new Main();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly
10
+ }
11
+
12
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Main' ) ) :
13
+
14
+ class Main {
15
+
16
+ function __construct() {
17
+ add_action( 'wp_ajax_generate_wpo_wcpdf', array($this, 'generate_pdf_ajax' ) );
18
+ add_filter( 'woocommerce_email_attachments', array( $this, 'attach_pdf_to_email' ), 99, 3 );
19
+ add_filter( 'wpo_wcpdf_custom_attachment_condition', array( $this, 'disable_free_attachment'), 10, 4 );
20
+
21
+ if ( isset(WPO_WCPDF()->settings->debug_settings['enable_debug']) ) {
22
+ $this->enable_debug();
23
+ }
24
+ if ( isset(WPO_WCPDF()->settings->debug_settings['html_output']) ) {
25
+ add_filter( 'wpo_wcpdf_use_path', '__return_false' );
26
+ }
27
+
28
+ // include template specific custom functions
29
+ $template_path = WPO_WCPDF()->settings->get_template_path();
30
+ if ( file_exists( $template_path . '/template-functions.php' ) ) {
31
+ require_once( $template_path . '/template-functions.php' );
32
+ }
33
+
34
+ // page numbers & currency filters
35
+ add_action( 'wpo_wcpdf_get_html', array($this, 'format_page_number_placeholders' ), 10, 2 );
36
+ add_action( 'wpo_wcpdf_after_dompdf_render', array($this, 'page_number_replacements' ), 9, 2 );
37
+ if ( isset( WPO_WCPDF()->settings->general_settings['currency_font'] ) ) {
38
+ add_action( 'wpo_wcpdf_before_pdf', array($this, 'use_currency_font' ), 10, 2 );
39
+ }
40
+
41
+ // scheduled attachments cleanup - disabled for now
42
+ // add_action( 'wp_scheduled_delete', array( $this, 'attachments_cleanup') );
43
+ }
44
+
45
+ /**
46
+ * Attach PDF to WooCommerce email
47
+ */
48
+ public function attach_pdf_to_email ( $attachments, $email_id, $order ) {
49
+ // check if all variables properly set
50
+ if ( !is_object( $order ) || !isset( $email_id ) ) {
51
+ return $attachments;
52
+ }
53
+
54
+ // Skip User emails
55
+ if ( get_class( $order ) == 'WP_User' ) {
56
+ return $attachments;
57
+ }
58
+
59
+ $order_id = WCX_Order::get_id( $order );
60
+
61
+ if ( get_class( $order ) !== 'WC_Order' && $order_id == false ) {
62
+ return $attachments;
63
+ }
64
+
65
+ // WooCommerce Booking compatibility
66
+ if ( get_post_type( $order_id ) == 'wc_booking' && isset($order->order) ) {
67
+ // $order is actually a WC_Booking object!
68
+ $order = $order->order;
69
+ }
70
+
71
+ // do not process low stock notifications, user emails etc!
72
+ if ( in_array( $email_id, array( 'no_stock', 'low_stock', 'backorder', 'customer_new_account', 'customer_reset_password' ) ) || get_post_type( $order_id ) != 'shop_order' ) {
73
+ return $attachments;
74
+ }
75
+
76
+ $tmp_path = $this->get_tmp_path('attachments');
77
+
78
+ // clear pdf files from temp folder (from http://stackoverflow.com/a/13468943/1446634)
79
+ // array_map('unlink', ( glob( $tmp_path.'*.pdf' ) ? glob( $tmp_path.'*.pdf' ) : array() ) );
80
+
81
+ // disable deprecation notices during email sending
82
+ add_filter( 'wcpdf_disable_deprecation_notices', '__return_true' );
83
+
84
+ $attach_to_document_types = $this->get_documents_for_email( $email_id, $order );
85
+ foreach ( $attach_to_document_types as $document_type ) {
86
+ do_action( 'wpo_wcpdf_before_attachment_creation', $order, $email_id, $document_type );
87
+
88
+ try {
89
+ // prepare document
90
+ $document = wcpdf_get_document( $document_type, (array) $order_id, true );
91
+ if ( !$document ) { // something went wrong, continue trying with other documents
92
+ continue;
93
+ }
94
+
95
+ // get pdf data & store
96
+ $pdf_data = $document->get_pdf();
97
+ $filename = $document->get_filename();
98
+ $pdf_path = $tmp_path . $filename;
99
+ file_put_contents ( $pdf_path, $pdf_data );
100
+ $attachments[] = $pdf_path;
101
+
102
+ do_action( 'wpo_wcpdf_email_attachment', $pdf_path, $document_type );
103
+ } catch (Exception $e) {
104
+ error_log($e->getMessage());
105
+ continue;
106
+ }
107
+ }
108
+
109
+ remove_filter( 'wcpdf_disable_deprecation_notices', '__return_true' );
110
+
111
+ return $attachments;
112
+ }
113
+
114
+ public function get_documents_for_email( $email_id, $order ) {
115
+ $documents = WPO_WCPDF()->documents->get_documents();
116
+
117
+ $attach_documents = array();
118
+ foreach ($documents as $document) {
119
+ $attach_documents[ $document->get_type() ] = $document->get_attach_to_email_ids();
120
+ }
121
+ $attach_documents = apply_filters('wpo_wcpdf_attach_documents', $attach_documents );
122
+
123
+ $document_types = array();
124
+ foreach ($attach_documents as $document_type => $attach_to_email_ids ) {
125
+ // legacy settings: convert abbreviated email_ids
126
+ foreach ($attach_to_email_ids as $key => $attach_to_email_id) {
127
+ if ($attach_to_email_id == 'completed' || $attach_to_email_id == 'processing') {
128
+ $attach_to_email_ids[$key] = "customer_" . $attach_to_email_id . "_order";
129
+ }
130
+ }
131
+
132
+ $extra_condition = apply_filters('wpo_wcpdf_custom_attachment_condition', true, $order, $email_id, $document_type );
133
+ if ( in_array( $email_id, $attach_to_email_ids ) && $extra_condition === true ) {
134
+ $document_types[] = $document_type;
135
+ }
136
+ }
137
+
138
+ return $document_types;
139
+ }
140
+
141
+ /**
142
+ * Load and generate the template output with ajax
143
+ */
144
+ public function generate_pdf_ajax() {
145
+ // Check the nonce
146
+ if( empty( $_GET['action'] ) || !check_admin_referer( $_GET['action'] ) ) {
147
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ) );
148
+ }
149
+
150
+ // Check if all parameters are set
151
+ if ( empty( $_GET['document_type'] ) && !empty( $_GET['template_type'] ) ) {
152
+ $_GET['document_type'] = $_GET['template_type'];
153
+ }
154
+
155
+ if ( empty( $_GET['order_ids'] ) ) {
156
+ wp_die( __( "You haven't selected any orders", 'woocommerce-pdf-invoices-packing-slips' ) );
157
+ }
158
+
159
+ if( empty( $_GET['document_type'] ) ) {
160
+ wp_die( __( 'Some of the export parameters are missing.', 'woocommerce-pdf-invoices-packing-slips' ) );
161
+ }
162
+
163
+ // Generate the output
164
+ $document_type = $_GET['document_type'];
165
+
166
+ $order_ids = (array) explode('x',$_GET['order_ids']);
167
+ // Process oldest first: reverse $order_ids array
168
+ $order_ids = array_reverse($order_ids);
169
+
170
+ // set default is allowed
171
+ $allowed = true;
172
+
173
+ // check if user is logged in
174
+ if ( ! is_user_logged_in() ) {
175
+ $allowed = false;
176
+ }
177
+
178
+ // Check the user privileges
179
+ if( !( current_user_can( 'manage_woocommerce_orders' ) || current_user_can( 'edit_shop_orders' ) ) && !isset( $_GET['my-account'] ) ) {
180
+ $allowed = false;
181
+ }
182
+
183
+ // User call from my-account page
184
+ if ( !current_user_can('manage_options') && isset( $_GET['my-account'] ) ) {
185
+ // Only for single orders!
186
+ if ( count( $order_ids ) > 1 ) {
187
+ $allowed = false;
188
+ }
189
+
190
+ // Check if current user is owner of order IMPORTANT!!!
191
+ if ( ! current_user_can( 'view_order', $order_ids[0] ) ) {
192
+ $allowed = false;
193
+ }
194
+ }
195
+
196
+ $allowed = apply_filters( 'wpo_wcpdf_check_privs', $allowed, $order_ids );
197
+
198
+ if ( ! $allowed ) {
199
+ wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce-pdf-invoices-packing-slips' ) );
200
+ }
201
+
202
+ // if we got here, we're safe to go!
203
+ try {
204
+ $document = wcpdf_get_document( $document_type, $order_ids, true );
205
+
206
+ if ( $document ) {
207
+ $output_format = WPO_WCPDF()->settings->get_output_format( $document_type );
208
+ switch ( $output_format ) {
209
+ case 'html':
210
+ $document->output_html();
211
+ break;
212
+ case 'pdf':
213
+ default:
214
+ if ( has_action( 'wpo_wcpdf_created_manually' ) ) {
215
+ do_action( 'wpo_wcpdf_created_manually', $document->get_pdf(), $document->get_filename() );
216
+ }
217
+ $output_mode = WPO_WCPDF()->settings->get_output_mode( $document_type );
218
+ $document->output_pdf( $output_mode );
219
+ break;
220
+ }
221
+ } else {
222
+ wp_die( sprintf( __( "Document of type '%s' for the selected order(s) could not be generated", 'woocommerce-pdf-invoices-packing-slips' ), $document_type ) );
223
+ }
224
+ } catch (Exception $e) {
225
+ echo $e->getMessage();
226
+ }
227
+
228
+ exit;
229
+ }
230
+
231
+ /**
232
+ * Return tmp path for different plugin processes
233
+ */
234
+ public function get_tmp_path ( $type = '' ) {
235
+ $tmp_base = $this->get_tmp_base();
236
+ // check if tmp folder exists => if not, initialize
237
+ if ( !@is_dir( $tmp_base ) ) {
238
+ $this->init_tmp( $tmp_base );
239
+ }
240
+
241
+ if ( empty( $type ) ) {
242
+ return $tmp_base;
243
+ }
244
+
245
+ switch ( $type ) {
246
+ case 'dompdf':
247
+ $tmp_path = $tmp_base . 'dompdf';
248
+ break;
249
+ case 'font_cache':
250
+ case 'fonts':
251
+ $tmp_path = $tmp_base . 'fonts';
252
+ break;
253
+ case 'attachments':
254
+ $tmp_path = $tmp_base . 'attachments/';
255
+ break;
256
+ default:
257
+ $tmp_path = $tmp_base . $type;
258
+ break;
259
+ }
260
+
261
+ // double check for existence, in case tmp_base was installed, but subfolder not created
262
+ if ( !@is_dir( $tmp_path ) ) {
263
+ @mkdir( $tmp_path );
264
+ }
265
+
266
+ return $tmp_path;
267
+ }
268
+
269
+ /**
270
+ * return the base tmp folder (usually uploads)
271
+ */
272
+ public function get_tmp_base () {
273
+ // wp_upload_dir() is used to set the base temp folder, under which a
274
+ // 'wpo_wcpdf' folder and several subfolders are created
275
+ //
276
+ // wp_upload_dir() will:
277
+ // * default to WP_CONTENT_DIR/uploads
278
+ // * UNLESS the ‘UPLOADS’ constant is defined in wp-config (http://codex.wordpress.org/Editing_wp-config.php#Moving_uploads_folder)
279
+ //
280
+ // May also be overridden by the wpo_wcpdf_tmp_path filter
281
+
282
+ $upload_dir = wp_upload_dir();
283
+ $upload_base = trailingslashit( $upload_dir['basedir'] );
284
+ $tmp_base = trailingslashit( apply_filters( 'wpo_wcpdf_tmp_path', $upload_base . 'wpo_wcpdf/' ) );
285
+ return $tmp_base;
286
+ }
287
+
288
+ /**
289
+ * Install/create plugin tmp folders
290
+ */
291
+ public function init_tmp ( $tmp_base ) {
292
+ // create plugin base temp folder
293
+ @mkdir( $tmp_base );
294
+
295
+ // create subfolders & protect
296
+ $subfolders = array( 'attachments', 'fonts', 'dompdf' );
297
+ foreach ( $subfolders as $subfolder ) {
298
+ $path = $tmp_base . $subfolder . '/';
299
+ @mkdir( $path );
300
+
301
+ // copy font files
302
+ if ( $subfolder == 'fonts' ) {
303
+ $this->copy_fonts( $path, false );
304
+ }
305
+
306
+ // create .htaccess file and empty index.php to protect in case an open webfolder is used!
307
+ @file_put_contents( $path . '.htaccess', 'deny from all' );
308
+ @touch( $path . 'index.php' );
309
+ }
310
+
311
+ }
312
+
313
+ /**
314
+ * Copy DOMPDF fonts to wordpress tmp folder
315
+ */
316
+ public function copy_fonts ( $path, $merge_with_local = true ) {
317
+ $path = trailingslashit( $path );
318
+ $dompdf_font_dir = WPO_WCPDF()->plugin_path() . "/vendor/dompdf/dompdf/lib/fonts/";
319
+
320
+ // get local font dir from filtered options
321
+ $dompdf_options = apply_filters( 'wpo_wcpdf_dompdf_options', array(
322
+ 'defaultFont' => 'dejavu sans',
323
+ 'tempDir' => $this->get_tmp_path('dompdf'),
324
+ 'logOutputFile' => $this->get_tmp_path('dompdf') . "/log.htm",
325
+ 'fontDir' => $this->get_tmp_path('fonts'),
326
+ 'fontCache' => $this->get_tmp_path('fonts'),
327
+ 'isRemoteEnabled' => true,
328
+ 'isFontSubsettingEnabled' => true,
329
+ 'isHtml5ParserEnabled' => true,
330
+ ) );
331
+ $fontDir = $dompdf_options['fontDir'];
332
+
333
+ // merge font family cache with local/custom if present
334
+ $font_cache_files = array(
335
+ 'cache' => 'dompdf_font_family_cache.php',
336
+ 'cache_dist' => 'dompdf_font_family_cache.dist.php',
337
+ );
338
+ foreach ( $font_cache_files as $font_cache_name => $font_cache_filename ) {
339
+ $plugin_fonts = @require $dompdf_font_dir . $font_cache_filename;
340
+ if ( $merge_with_local && is_readable( $path . $font_cache_filename ) ) {
341
+ $local_fonts = @require $path . $font_cache_filename;
342
+ if (is_array($local_fonts) && is_array($plugin_fonts)) {
343
+ // merge local & plugin fonts, plugin fonts overwrite (update) local fonts
344
+ // while custom local fonts are retained
345
+ $local_fonts = array_merge($local_fonts, $plugin_fonts);
346
+ // create readable array with $fontDir in place of the actual folder for portability
347
+ $fonts_export = var_export($local_fonts,true);
348
+ $fonts_export = str_replace('\'' . $fontDir , '$fontDir . \'', $fonts_export);
349
+ $cacheData = sprintf("<?php return %s;%s?>", $fonts_export, PHP_EOL );
350
+ // write file with merged cache data
351
+ file_put_contents($path . $font_cache_filename, $cacheData);
352
+ } else { // empty local file
353
+ copy( $dompdf_font_dir . $font_cache_filename, $path . $font_cache_filename );
354
+ }
355
+ } else {
356
+ // we couldn't read the local font cache file so we're simply copying over plugin cache file
357
+ copy( $dompdf_font_dir . $font_cache_filename, $path . $font_cache_filename );
358
+ }
359
+ }
360
+
361
+ // first try the easy way with glob!
362
+ if ( function_exists('glob') ) {
363
+ $files = glob($dompdf_font_dir."*.*");
364
+ foreach($files as $file){
365
+ $filename = basename($file);
366
+ if( !is_dir($file) && is_readable($file) && !in_array($filename, $font_cache_files)) {
367
+ $dest = $path . $filename;
368
+ copy($file, $dest);
369
+ }
370
+ }
371
+ } else {
372
+ // fallback method using font cache file (glob is disabled on some servers with disable_functions)
373
+ $extensions = array( '.ttf', '.ufm', '.ufm.php', '.afm', '.afm.php' );
374
+ $fontDir = untrailingslashit($dompdf_font_dir);
375
+ $plugin_fonts = @require $dompdf_font_dir . $font_cache_files['cache'];
376
+
377
+ foreach ($plugin_fonts as $font_family => $filenames) {
378
+ foreach ($filenames as $filename) {
379
+ foreach ($extensions as $extension) {
380
+ $file = $filename.$extension;
381
+ if (file_exists($file)) {
382
+ $dest = $path . basename($file);
383
+ copy($file, $dest);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ public function disable_free_attachment( $attach, $order, $email_id, $document_type ) {
392
+ // prevent fatal error for non-order objects
393
+ if ( !method_exists( $order, 'get_total' ) ) {
394
+ return false;
395
+ }
396
+
397
+ $document_settings = WPO_WCPDF()->settings->get_document_settings( $document_type );
398
+ // echo '<pre>';var_dump($document_type);echo '</pre>';
399
+ // error_log( var_export($document_settings,true) );
400
+
401
+ // check order total & setting
402
+ $order_total = $order->get_total();
403
+ if ( $order_total == 0 && isset( $document_settings['disable_free'] ) ) {
404
+ return false;
405
+ }
406
+
407
+ return $attach;
408
+ }
409
+
410
+ /**
411
+ * Adds spans around placeholders to be able to make replacement (page count) and css (page number)
412
+ */
413
+ public function format_page_number_placeholders ( $html, $document ) {
414
+ $html = str_replace('{{PAGE_COUNT}}', '<span class="pagecount">^C^</span>', $html);
415
+ $html = str_replace('{{PAGE_NUM}}', '<span class="pagenum"></span>', $html );
416
+ return $html;
417
+ }
418
+
419
+ /**
420
+ * Replace {{PAGE_COUNT}} placeholder with total page count
421
+ */
422
+ public function page_number_replacements ( $dompdf, $html ) {
423
+ $placeholder = '^C^';
424
+ // create placeholder version with ASCII 0 spaces (dompdf 0.8)
425
+ $placeholder_0 = '';
426
+ $placeholder_chars = str_split($placeholder);
427
+ foreach ($placeholder_chars as $placeholder_char) {
428
+ $placeholder_0 .= chr(0).$placeholder_char;
429
+ }
430
+
431
+ // check if placeholder is used
432
+ if (strpos($html, $placeholder) !== false ) {
433
+ foreach ($dompdf->get_canvas()->get_cpdf()->objects as &$object) {
434
+ if (array_key_exists("c", $object) && strpos($object["c"], $placeholder) !== false ) {
435
+ $object["c"] = str_replace( array($placeholder,$placeholder_0) , $dompdf->get_canvas()->get_page_count() , $object["c"] );
436
+ } elseif (array_key_exists("c", $object) && strpos($object["c"], $placeholder_0) !== false ) {
437
+ $object["c"] = str_replace( array($placeholder,$placeholder_0) , chr(0).$dompdf->get_canvas()->get_page_count() , $object["c"] );
438
+ }
439
+ }
440
+ }
441
+
442
+ return $dompdf;
443
+ }
444
+
445
+ /**
446
+ * Use currency symbol font (when enabled in options)
447
+ */
448
+ public function use_currency_font ( $document_type, $document ) {
449
+ add_filter( 'woocommerce_currency_symbol', array( $this, 'wrap_currency_symbol' ), 10, 2);
450
+ add_action( 'wpo_wcpdf_custom_styles', array($this, 'currency_symbol_font_styles' ) );
451
+ }
452
+
453
+ public function wrap_currency_symbol( $currency_symbol, $currency ) {
454
+ $currency_symbol = sprintf( '<span class="wcpdf-currency-symbol">%s</span>', $currency_symbol );
455
+ return $currency_symbol;
456
+ }
457
+
458
+ public function currency_symbol_font_styles () {
459
+ ?>
460
+ .wcpdf-currency-symbol { font-family: 'Currencies'; }
461
+ <?php
462
+ }
463
+
464
+ /**
465
+ * Remove attachments older than 1 week (daily, hooked into wp_scheduled_delete )
466
+ */
467
+ public function attachments_cleanup() {
468
+ if ( !function_exists("glob") || !function_exists('filemtime')) {
469
+ // glob is disabled
470
+ return;
471
+ }
472
+
473
+ $delete_timestamp = time() - ( DAY_IN_SECONDS * 7 );
474
+
475
+ $tmp_path = $this->get_tmp_path('attachments');
476
+
477
+ if ( $files = glob( $tmp_path.'*.pdf' ) ) { // get all pdf files
478
+ foreach( $files as $file ) {
479
+ if( is_file( $file ) ) {
480
+ $file_timestamp = filemtime( $file );
481
+ if ( !empty( $file_timestamp ) && $file_timestamp < $delete_timestamp ) {
482
+ @unlink($file);
483
+ }
484
+ }
485
+ }
486
+ }
487
+
488
+ }
489
+
490
+ /**
491
+ * Enable PHP error output
492
+ */
493
+ public function enable_debug () {
494
+ error_reporting( E_ALL );
495
+ ini_set( 'display_errors', 1 );
496
+ }
497
+
498
+ }
499
+
500
+ endif; // class_exists
501
+
502
+ return new Main();
includes/class-wcpdf-pdf-maker.php CHANGED
@@ -41,6 +41,7 @@ class PDF_Maker {
41
  'fontCache' => WPO_WCPDF()->main->get_tmp_path('fonts'),
42
  'isRemoteEnabled' => true,
43
  'isFontSubsettingEnabled' => $this->settings['font_subsetting'],
 
44
  ) ) );
45
 
46
  // instantiate and use the dompdf class
41
  'fontCache' => WPO_WCPDF()->main->get_tmp_path('fonts'),
42
  'isRemoteEnabled' => true,
43
  'isFontSubsettingEnabled' => $this->settings['font_subsetting'],
44
+ 'isHtml5ParserEnabled' => true,
45
  ) ) );
46
 
47
  // instantiate and use the dompdf class
includes/class-wcpdf-settings-callbacks.php CHANGED
@@ -1,504 +1,503 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
5
-
6
- if ( ! defined( 'ABSPATH' ) ) {
7
- exit; // Exit if accessed directly
8
- }
9
-
10
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings_Callbacks' ) ) :
11
-
12
- class Settings_Callbacks {
13
- /**
14
- * Section null callback.
15
- *
16
- * @return void.
17
- */
18
- public function section() {
19
- }
20
-
21
- /**
22
- * Debug section callback.
23
- *
24
- * @return void.
25
- */
26
- public function debug_section() {
27
- _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'woocommerce-pdf-invoices-packing-slips' );
28
- }
29
-
30
- /**
31
- * Custom fields section callback.
32
- *
33
- * @return void.
34
- */
35
- public function custom_fields_section() {
36
- _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' , 'woocommerce-pdf-invoices-packing-slips' );
37
- }
38
-
39
- /**
40
- * Checkbox callback.
41
- *
42
- * args:
43
- * option_name - name of the main option
44
- * id - key of the setting
45
- * value - value if not 1 (optional)
46
- * default - default setting (optional)
47
- * description - description (optional)
48
- *
49
- * @return void.
50
- */
51
- public function checkbox( $args ) {
52
- extract( $this->normalize_settings_args( $args ) );
53
-
54
- // output checkbox
55
- printf( '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $value, checked( $value, $current, false ) );
56
-
57
- // output description.
58
- if ( isset( $description ) ) {
59
- printf( '<p class="description">%s</p>', $description );
60
- }
61
- }
62
-
63
- /**
64
- * Text input callback.
65
- *
66
- * args:
67
- * option_name - name of the main option
68
- * id - key of the setting
69
- * size - size of the text input (em)
70
- * default - default setting (optional)
71
- * description - description (optional)
72
- * type - type (optional)
73
- *
74
- * @return void.
75
- */
76
- public function text_input( $args ) {
77
- extract( $this->normalize_settings_args( $args ) );
78
-
79
- if (empty($type)) {
80
- $type = 'text';
81
- }
82
-
83
- printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" size="%5$s" placeholder="%6$s"/>', $type, $id, $setting_name, esc_attr( $current ), $size, $placeholder );
84
-
85
- // output description.
86
- if ( isset( $description ) ) {
87
- printf( '<p class="description">%s</p>', $description );
88
- }
89
- }
90
-
91
- // Single text option (not part of any settings array)
92
- public function singular_text_element( $args ) {
93
- $option_name = $args['option_name'];
94
- $id = $args['id'];
95
- $size = isset( $args['size'] ) ? $args['size'] : '25';
96
- $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
97
-
98
- $option = get_option( $option_name );
99
-
100
- if ( isset( $option ) ) {
101
- $current = $option;
102
- } else {
103
- $current = isset( $args['default'] ) ? $args['default'] : '';
104
- }
105
-
106
- $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $option_name, $current, $size, $class );
107
-
108
- // Displays option description.
109
- if ( isset( $args['description'] ) ) {
110
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
111
- }
112
-
113
- echo $html;
114
- }
115
-
116
-
117
- /**
118
- * Textarea callback.
119
- *
120
- * args:
121
- * option_name - name of the main option
122
- * id - key of the setting
123
- * width - width of the text input (em)
124
- * height - height of the text input (lines)
125
- * default - default setting (optional)
126
- * description - description (optional)
127
- *
128
- * @return void.
129
- */
130
- public function textarea( $args ) {
131
- extract( $this->normalize_settings_args( $args ) );
132
-
133
- printf( '<textarea id="%1$s" name="%2$s" cols="%4$s" rows="%5$s" placeholder="%6$s"/>%3$s</textarea>', $id, $setting_name, esc_textarea( $current ), $width, $height, $placeholder );
134
-
135
- // output description.
136
- if ( isset( $description ) ) {
137
- printf( '<p class="description">%s</p>', $description );
138
- }
139
- }
140
-
141
- /**
142
- * Select element callback.
143
- *
144
- * @param array $args Field arguments.
145
- *
146
- * @return string Select field.
147
- */
148
- public function select( $args ) {
149
- extract( $this->normalize_settings_args( $args ) );
150
-
151
- printf( '<select id="%1$s" name="%2$s">', $id, $setting_name );
152
-
153
- foreach ( $options as $key => $label ) {
154
- printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
155
- }
156
-
157
- echo '</select>';
158
-
159
- if (isset($custom)) {
160
- printf( '<div class="%1$s_custom custom">', $id );
161
-
162
- if (is_callable( array( $this, $custom['type'] ) ) ) {
163
- $this->{$custom['type']}( $custom['args'] );
164
- }
165
- echo '</div>';
166
- ?>
167
- <script type="text/javascript">
168
- jQuery(document).ready(function($) {
169
- function check_<?php echo $id; ?>_custom() {
170
- var custom = $('#<?php echo $id; ?>').val();
171
- console.log(custom);
172
- if (custom == 'custom') {
173
- $( '.<?php echo $id; ?>_custom').show();
174
- } else {
175
- $( '.<?php echo $id; ?>_custom').hide();
176
- }
177
- }
178
-
179
- check_<?php echo $id; ?>_custom();
180
-
181
- $( '#<?php echo $id; ?>' ).change(function() {
182
- check_<?php echo $id; ?>_custom();
183
- });
184
-
185
- });
186
- </script>
187
- <?php
188
- }
189
-
190
- // Displays option description.
191
- if ( isset( $args['description'] ) ) {
192
- printf( '<p class="description">%s</p>', $args['description'] );
193
- }
194
-
195
- }
196
-
197
- public function radio_button( $args ) {
198
- extract( $this->normalize_settings_args( $args ) );
199
-
200
- foreach ( $options as $key => $label ) {
201
- printf( '<input type="radio" class="radio" id="%1$s[%3$s]" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $key, checked( $current, $key, false ) );
202
- printf( '<label for="%1$s[%3$s]"> %4$s</label><br>', $id, $setting_name, $key, $label);
203
- }
204
-
205
-
206
- // Displays option description.
207
- if ( isset( $args['description'] ) ) {
208
- printf( '<p class="description">%s</p>', $args['description'] );
209
- }
210
-
211
- }
212
-
213
- /**
214
- * Multiple text element callback.
215
- * @param array $args Field arguments.
216
- * @return string Text input field.
217
- */
218
- public function multiple_text_input( $args ) {
219
- extract( $this->normalize_settings_args( $args ) );
220
-
221
- if (!empty($header)) {
222
- echo "<p><strong>{$header}</strong>:</p>";
223
- }
224
-
225
- printf('<p class="%s multiple-text-input">', $id);
226
- foreach ($fields as $name => $field) {
227
- $size = $field['size'];
228
- $placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
229
-
230
- if (isset($field['label_width'])) {
231
- $style = sprintf( 'style="display:inline-block; width:%1$s;"', $field['label_width'] );
232
- } else {
233
- $style = '';
234
- }
235
-
236
- $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
237
-
238
- // output field label
239
- if (isset($field['label'])) {
240
- printf( '<label for="%1$s_%2$s" %3$s>%4$s:</label>', $id, $name, $style, $field['label'] );
241
- }
242
-
243
- // output field
244
- $field_current = isset($current[$name]) ? $current[$name] : '';
245
- $type = isset( $field['type'] ) ? $field['type'] : 'text';
246
- printf( '<input type="%1$s" id="%2$s_%4$s" name="%3$s[%4$s]" value="%5$s" size="%6$s" placeholder="%7$s"/> %8$s<br/>', $type, $id, $setting_name, $name, esc_attr( $field_current ), $size, $placeholder, $description );
247
- }
248
- echo "</p>";
249
-
250
- // Displays option description.
251
- if ( isset( $args['description'] ) ) {
252
- printf( '<p class="description">%s</p>', $args['description'] );
253
- }
254
- }
255
-
256
- /**
257
- * Multiple text element callback.
258
- * @param array $args Field arguments.
259
- * @return string Text input field.
260
- */
261
- public function multiple_checkboxes( $args ) {
262
- extract( $this->normalize_settings_args( $args ) );
263
-
264
- foreach ($fields as $name => $label) {
265
- // $label = $field['label'];
266
-
267
- // output checkbox
268
- $field_current = isset($current[$name]) ? $current[$name] : '';
269
- printf( '<input type="checkbox" id="%1$s_%3$s" name="%2$s[%3$s]" value="%4$s"%5$s />', $id, $setting_name, $name, $value, checked( $value, $field_current, false ) );
270
-
271
- // output field label
272
- printf( '<label for="%1$s_%2$s">%3$s</label><br>', $id, $name, $label );
273
-
274
- }
275
-
276
- // Displays option description.
277
- if ( isset( $args['description'] ) ) {
278
- printf( '<p class="description">%s</p>', $args['description'] );
279
- }
280
- }
281
-
282
- /**
283
- * Media upload callback.
284
- *
285
- * @param array $args Field arguments.
286
- *
287
- * @return string Media upload button & preview.
288
- */
289
- public function media_upload( $args ) {
290
- extract( $this->normalize_settings_args( $args ) );
291
-
292
- if( !empty($current) ) {
293
- $attachment = wp_get_attachment_image_src( $current, 'thumbnail', false );
294
-
295
- $attachment_src = $attachment[0];
296
- $attachment_width = $attachment[1];
297
- $attachment_height = $attachment[2];
298
- $attachment_resolution = round($attachment_height/(3/2.54));
299
-
300
- printf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
301
- printf('<div class="attachment-resolution"><p class="description">%s: %sdpi (default height = 3cm)</p></div>', __('Image resolution'), $attachment_resolution );
302
- printf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
303
- }
304
-
305
- printf( '<input id="%1$s" name="%2$s" type="hidden" value="%3$s" />', $id, $setting_name, $current );
306
-
307
- printf( '<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 );
308
-
309
- // Displays option description.
310
- if ( isset( $description ) ) {
311
- printf( '<p class="description">%s</p>', $description );
312
- }
313
- }
314
-
315
- /**
316
- * Next document number edit callback.
317
- *
318
- * @param array $args Field arguments.
319
- */
320
- public function next_number_edit( $args ) {
321
- extract( $args );
322
- $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
323
- $number_store = new Sequential_Number_Store( $store, $number_store_method );
324
- $next_number = $number_store->get_next();
325
- $nonce = wp_create_nonce( "wpo_wcpdf_next_{$store}" );
326
- printf( '<input id="next_%1$s" class="next-number-input" type="text" size="%2$s" value="%3$s" disabled="disabled" data-store="%1$s" data-nonce="%4$s"/> <span class="edit-next-number dashicons dashicons-edit"></span><span class="save-next-number button secondary" style="display:none;">%5$s</span>', $store, $size, $next_number, $nonce, __( 'Save', 'woocommerce-pdf-invoices-packing-slips' ) );
327
- // Displays option description.
328
- if ( isset( $description ) ) {
329
- printf( '<p class="description">%s</p>', $description );
330
- }
331
- }
332
-
333
- /**
334
- * Wrapper function to create tabs for settings in different languages
335
- * @param [type] $args [description]
336
- * @param [type] $callback [description]
337
- * @return [type] [description]
338
- */
339
- public function i18n_wrap ( $args ) {
340
- extract( $this->normalize_settings_args( $args ) );
341
-
342
- if ( $languages = $this->get_languages() ) {
343
- printf( '<div id="%s-%s-translations" class="translations">', $option_name, $id)
344
- ?>
345
- <ul>
346
- <?php foreach ( $languages as $lang_code => $language_name ) {
347
- $translation_id = "{$option_name}_{$id}_{$lang_code}";
348
- printf('<li><a href="#%s">%s</a></li>', $translation_id, $language_name );
349
- }
350
- ?>
351
- </ul>
352
- <?php foreach ( $languages as $lang_code => $language_name ) {
353
- $translation_id = "{$option_name}_{$id}_{$lang_code}";
354
- printf( '<div id="%s">', $translation_id );
355
- $args['lang'] = $lang_code;
356
- // don't use internationalized placeholders since they're not translated,
357
- // to avoid confusion (user thinking they're all the same)
358
- if ( $callback == 'multiple_text_input' ) {
359
- foreach ($fields as $key => $field_args) {
360
- if (!empty($field_args['placeholder']) && isset($field_args['i18n_placeholder'])) {
361
- $args['fields'][$key]['placeholder'] = '';
362
- }
363
- }
364
- } else {
365
- if (!empty($args['placeholder']) && isset($args['i18n_placeholder'])) {
366
- $args['placeholder'] = '';
367
- }
368
- }
369
- // specific description for internationalized fields (to compensate for missing placeholder)
370
- if (!empty($args['i18n_description'])) {
371
- $args['description'] = $args['i18n_description'];
372
- }
373
- call_user_func( array( $this, $callback ), $args );
374
- echo '</div>';
375
- }
376
- ?>
377
-
378
- </div>
379
- <?php
380
- } else {
381
- $args['lang'] = 'default';
382
- call_user_func( array( $this, $callback ), $args );
383
- }
384
- }
385
-
386
- public function get_languages () {
387
- $multilingual = function_exists('icl_get_languages');
388
- // $multilingual = true; // for development
389
-
390
- if ($multilingual) {
391
- // use this instead of function call for development outside of WPML
392
- // $icl_get_languages = 'a:3:{s:2:"en";a:8:{s:2:"id";s:1:"1";s:6:"active";s:1:"1";s:11:"native_name";s:7:"English";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"English";s:13:"language_code";s:2:"en";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/en.png";s:3:"url";s:23:"http://yourdomain/about";}s:2:"fr";a:8:{s:2:"id";s:1:"4";s:6:"active";s:1:"0";s:11:"native_name";s:9:"Français";s:7:"missing";s:1:"0";s:15:"translated_name";s:6:"French";s:13:"language_code";s:2:"fr";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/fr.png";s:3:"url";s:29:"http://yourdomain/fr/a-propos";}s:2:"it";a:8:{s:2:"id";s:2:"27";s:6:"active";s:1:"0";s:11:"native_name";s:8:"Italiano";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"Italian";s:13:"language_code";s:2:"it";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/it.png";s:3:"url";s:26:"http://yourdomain/it/circa";}}';
393
- // $icl_get_languages = unserialize($icl_get_languages);
394
-
395
- $icl_get_languages = icl_get_languages('skip_missing=0');
396
- $languages = array();
397
- foreach ($icl_get_languages as $lang => $data) {
398
- $languages[$data['language_code']] = $data['native_name'];
399
- }
400
- } else {
401
- return false;
402
- }
403
-
404
- return $languages;
405
- }
406
-
407
- public function normalize_settings_args ( $args ) {
408
- $args['value'] = isset( $args['value'] ) ? $args['value'] : 1;
409
-
410
- $args['placeholder'] = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
411
-
412
- // get main settings array
413
- $option = get_option( $args['option_name'] );
414
-
415
- $args['setting_name'] = "{$args['option_name']}[{$args['id']}]";
416
-
417
- if ( !isset($args['lang']) && !empty($args['translatable']) ) {
418
- $args['lang'] = 'default';
419
- }
420
-
421
- if (isset($args['lang'])) {
422
- // i18n settings name
423
- $args['setting_name'] = "{$args['setting_name']}[{$args['lang']}]";
424
- // copy current option value if set
425
-
426
- if ( $args['lang'] == 'default' && !empty($option[$args['id']]) && !isset( $option[$args['id']]['default'] ) ) {
427
- // we're switching back from WPML to normal
428
- // try english first
429
- if ( isset( $option[$args['id']]['en'] ) ) {
430
- $args['current'] = $option[$args['id']]['en'];
431
- } elseif ( is_array( $option[$args['id']] ) ) {
432
- // fallback to the first language if english not found
433
- $first = array_shift($option[$args['id']]);
434
- if (!empty($first)) {
435
- $args['current'] = $first;
436
- }
437
- } elseif ( is_string( $option[$args['id']] ) ) {
438
- $args['current'] = $option[$args['id']];
439
- } else {
440
- // nothing, really?
441
- $args['current'] = '';
442
- }
443
- } else {
444
- if ( isset( $option[$args['id']][$args['lang']] ) ) {
445
- $args['current'] = $option[$args['id']][$args['lang']];
446
- } elseif (isset( $option[$args['id']]['default'] )) {
447
- $args['current'] = $option[$args['id']]['default'];
448
- }
449
- }
450
- } else {
451
- // copy current option value if set
452
- if ( isset( $option[$args['id']] ) ) {
453
- $args['current'] = $option[$args['id']];
454
- }
455
- }
456
-
457
- // falback to default or empty if no value in option
458
- if ( !isset($args['current']) ) {
459
- $args['current'] = isset( $args['default'] ) ? $args['default'] : '';
460
- }
461
-
462
- return $args;
463
- }
464
-
465
- /**
466
- * Validate options.
467
- *
468
- * @param array $input options to valid.
469
- *
470
- * @return array validated options.
471
- */
472
- public function validate( $input ) {
473
- // echo '<pre>';var_dump($input);die('</pre>');
474
- // Create our array for storing the validated options.
475
- $output = array();
476
-
477
- if (empty($input) || !is_array($input)) {
478
- return $input;
479
- }
480
-
481
- // Loop through each of the incoming options.
482
- foreach ( $input as $key => $value ) {
483
-
484
- // Check to see if the current option has a value. If so, process it.
485
- if ( isset( $input[$key] ) ) {
486
- if ( is_array( $input[$key] ) ) {
487
- foreach ( $input[$key] as $sub_key => $sub_value ) {
488
- $output[$key][$sub_key] = $input[$key][$sub_key];
489
- }
490
- } else {
491
- $output[$key] = $input[$key];
492
- }
493
- }
494
- }
495
-
496
- // Return the array processing any additional functions filtered by this action.
497
- return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
498
- }
499
- }
500
-
501
-
502
- endif; // class_exists
503
-
504
  return new Settings_Callbacks();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit; // Exit if accessed directly
8
+ }
9
+
10
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings_Callbacks' ) ) :
11
+
12
+ class Settings_Callbacks {
13
+ /**
14
+ * Section null callback.
15
+ *
16
+ * @return void.
17
+ */
18
+ public function section() {
19
+ }
20
+
21
+ /**
22
+ * Debug section callback.
23
+ *
24
+ * @return void.
25
+ */
26
+ public function debug_section() {
27
+ _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'woocommerce-pdf-invoices-packing-slips' );
28
+ }
29
+
30
+ /**
31
+ * Custom fields section callback.
32
+ *
33
+ * @return void.
34
+ */
35
+ public function custom_fields_section() {
36
+ _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' , 'woocommerce-pdf-invoices-packing-slips' );
37
+ }
38
+
39
+ /**
40
+ * Checkbox callback.
41
+ *
42
+ * args:
43
+ * option_name - name of the main option
44
+ * id - key of the setting
45
+ * value - value if not 1 (optional)
46
+ * default - default setting (optional)
47
+ * description - description (optional)
48
+ *
49
+ * @return void.
50
+ */
51
+ public function checkbox( $args ) {
52
+ extract( $this->normalize_settings_args( $args ) );
53
+
54
+ // output checkbox
55
+ printf( '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $value, checked( $value, $current, false ) );
56
+
57
+ // output description.
58
+ if ( isset( $description ) ) {
59
+ printf( '<p class="description">%s</p>', $description );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Text input callback.
65
+ *
66
+ * args:
67
+ * option_name - name of the main option
68
+ * id - key of the setting
69
+ * size - size of the text input (em)
70
+ * default - default setting (optional)
71
+ * description - description (optional)
72
+ * type - type (optional)
73
+ *
74
+ * @return void.
75
+ */
76
+ public function text_input( $args ) {
77
+ extract( $this->normalize_settings_args( $args ) );
78
+
79
+ if (empty($type)) {
80
+ $type = 'text';
81
+ }
82
+
83
+ printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" size="%5$s" placeholder="%6$s"/>', $type, $id, $setting_name, esc_attr( $current ), $size, $placeholder );
84
+
85
+ // output description.
86
+ if ( isset( $description ) ) {
87
+ printf( '<p class="description">%s</p>', $description );
88
+ }
89
+ }
90
+
91
+ // Single text option (not part of any settings array)
92
+ public function singular_text_element( $args ) {
93
+ $option_name = $args['option_name'];
94
+ $id = $args['id'];
95
+ $size = isset( $args['size'] ) ? $args['size'] : '25';
96
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
97
+
98
+ $option = get_option( $option_name );
99
+
100
+ if ( isset( $option ) ) {
101
+ $current = $option;
102
+ } else {
103
+ $current = isset( $args['default'] ) ? $args['default'] : '';
104
+ }
105
+
106
+ $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $option_name, $current, $size, $class );
107
+
108
+ // Displays option description.
109
+ if ( isset( $args['description'] ) ) {
110
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
111
+ }
112
+
113
+ echo $html;
114
+ }
115
+
116
+
117
+ /**
118
+ * Textarea callback.
119
+ *
120
+ * args:
121
+ * option_name - name of the main option
122
+ * id - key of the setting
123
+ * width - width of the text input (em)
124
+ * height - height of the text input (lines)
125
+ * default - default setting (optional)
126
+ * description - description (optional)
127
+ *
128
+ * @return void.
129
+ */
130
+ public function textarea( $args ) {
131
+ extract( $this->normalize_settings_args( $args ) );
132
+
133
+ printf( '<textarea id="%1$s" name="%2$s" cols="%4$s" rows="%5$s" placeholder="%6$s"/>%3$s</textarea>', $id, $setting_name, esc_textarea( $current ), $width, $height, $placeholder );
134
+
135
+ // output description.
136
+ if ( isset( $description ) ) {
137
+ printf( '<p class="description">%s</p>', $description );
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Select element callback.
143
+ *
144
+ * @param array $args Field arguments.
145
+ *
146
+ * @return string Select field.
147
+ */
148
+ public function select( $args ) {
149
+ extract( $this->normalize_settings_args( $args ) );
150
+
151
+ printf( '<select id="%1$s" name="%2$s">', $id, $setting_name );
152
+
153
+ foreach ( $options as $key => $label ) {
154
+ printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
155
+ }
156
+
157
+ echo '</select>';
158
+
159
+ if (isset($custom)) {
160
+ printf( '<div class="%1$s_custom custom">', $id );
161
+
162
+ if (is_callable( array( $this, $custom['type'] ) ) ) {
163
+ $this->{$custom['type']}( $custom['args'] );
164
+ }
165
+ echo '</div>';
166
+ ?>
167
+ <script type="text/javascript">
168
+ jQuery(document).ready(function($) {
169
+ function check_<?php echo $id; ?>_custom() {
170
+ var custom = $('#<?php echo $id; ?>').val();
171
+ if (custom == 'custom') {
172
+ $( '.<?php echo $id; ?>_custom').show();
173
+ } else {
174
+ $( '.<?php echo $id; ?>_custom').hide();
175
+ }
176
+ }
177
+
178
+ check_<?php echo $id; ?>_custom();
179
+
180
+ $( '#<?php echo $id; ?>' ).change(function() {
181
+ check_<?php echo $id; ?>_custom();
182
+ });
183
+
184
+ });
185
+ </script>
186
+ <?php
187
+ }
188
+
189
+ // Displays option description.
190
+ if ( isset( $args['description'] ) ) {
191
+ printf( '<p class="description">%s</p>', $args['description'] );
192
+ }
193
+
194
+ }
195
+
196
+ public function radio_button( $args ) {
197
+ extract( $this->normalize_settings_args( $args ) );
198
+
199
+ foreach ( $options as $key => $label ) {
200
+ printf( '<input type="radio" class="radio" id="%1$s[%3$s]" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $key, checked( $current, $key, false ) );
201
+ printf( '<label for="%1$s[%3$s]"> %4$s</label><br>', $id, $setting_name, $key, $label);
202
+ }
203
+
204
+
205
+ // Displays option description.
206
+ if ( isset( $args['description'] ) ) {
207
+ printf( '<p class="description">%s</p>', $args['description'] );
208
+ }
209
+
210
+ }
211
+
212
+ /**
213
+ * Multiple text element callback.
214
+ * @param array $args Field arguments.
215
+ * @return string Text input field.
216
+ */
217
+ public function multiple_text_input( $args ) {
218
+ extract( $this->normalize_settings_args( $args ) );
219
+
220
+ if (!empty($header)) {
221
+ echo "<p><strong>{$header}</strong>:</p>";
222
+ }
223
+
224
+ printf('<p class="%s multiple-text-input">', $id);
225
+ foreach ($fields as $name => $field) {
226
+ $size = $field['size'];
227
+ $placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
228
+
229
+ if (isset($field['label_width'])) {
230
+ $style = sprintf( 'style="display:inline-block; width:%1$s;"', $field['label_width'] );
231
+ } else {
232
+ $style = '';
233
+ }
234
+
235
+ $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
236
+
237
+ // output field label
238
+ if (isset($field['label'])) {
239
+ printf( '<label for="%1$s_%2$s" %3$s>%4$s:</label>', $id, $name, $style, $field['label'] );
240
+ }
241
+
242
+ // output field
243
+ $field_current = isset($current[$name]) ? $current[$name] : '';
244
+ $type = isset( $field['type'] ) ? $field['type'] : 'text';
245
+ printf( '<input type="%1$s" id="%2$s_%4$s" name="%3$s[%4$s]" value="%5$s" size="%6$s" placeholder="%7$s"/> %8$s<br/>', $type, $id, $setting_name, $name, esc_attr( $field_current ), $size, $placeholder, $description );
246
+ }
247
+ echo "</p>";
248
+
249
+ // Displays option description.
250
+ if ( isset( $args['description'] ) ) {
251
+ printf( '<p class="description">%s</p>', $args['description'] );
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Multiple text element callback.
257
+ * @param array $args Field arguments.
258
+ * @return string Text input field.
259
+ */
260
+ public function multiple_checkboxes( $args ) {
261
+ extract( $this->normalize_settings_args( $args ) );
262
+
263
+ foreach ($fields as $name => $label) {
264
+ // $label = $field['label'];
265
+
266
+ // output checkbox
267
+ $field_current = isset($current[$name]) ? $current[$name] : '';
268
+ printf( '<input type="checkbox" id="%1$s_%3$s" name="%2$s[%3$s]" value="%4$s"%5$s />', $id, $setting_name, $name, $value, checked( $value, $field_current, false ) );
269
+
270
+ // output field label
271
+ printf( '<label for="%1$s_%2$s">%3$s</label><br>', $id, $name, $label );
272
+
273
+ }
274
+
275
+ // Displays option description.
276
+ if ( isset( $args['description'] ) ) {
277
+ printf( '<p class="description">%s</p>', $args['description'] );
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Media upload callback.
283
+ *
284
+ * @param array $args Field arguments.
285
+ *
286
+ * @return string Media upload button & preview.
287
+ */
288
+ public function media_upload( $args ) {
289
+ extract( $this->normalize_settings_args( $args ) );
290
+
291
+ if( !empty($current) ) {
292
+ $attachment = wp_get_attachment_image_src( $current, 'thumbnail', false );
293
+
294
+ $attachment_src = $attachment[0];
295
+ $attachment_width = $attachment[1];
296
+ $attachment_height = $attachment[2];
297
+ $attachment_resolution = round($attachment_height/(3/2.54));
298
+
299
+ printf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
300
+ printf('<div class="attachment-resolution"><p class="description">%s: %sdpi (default height = 3cm)</p></div>', __('Image resolution'), $attachment_resolution );
301
+ printf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
302
+ }
303
+
304
+ printf( '<input id="%1$s" name="%2$s" type="hidden" value="%3$s" />', $id, $setting_name, $current );
305
+
306
+ printf( '<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 );
307
+
308
+ // Displays option description.
309
+ if ( isset( $description ) ) {
310
+ printf( '<p class="description">%s</p>', $description );
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Next document number edit callback.
316
+ *
317
+ * @param array $args Field arguments.
318
+ */
319
+ public function next_number_edit( $args ) {
320
+ extract( $args );
321
+ $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
322
+ $number_store = new Sequential_Number_Store( $store, $number_store_method );
323
+ $next_number = $number_store->get_next();
324
+ $nonce = wp_create_nonce( "wpo_wcpdf_next_{$store}" );
325
+ printf( '<input id="next_%1$s" class="next-number-input" type="text" size="%2$s" value="%3$s" disabled="disabled" data-store="%1$s" data-nonce="%4$s"/> <span class="edit-next-number dashicons dashicons-edit"></span><span class="save-next-number button secondary" style="display:none;">%5$s</span>', $store, $size, $next_number, $nonce, __( 'Save', 'woocommerce-pdf-invoices-packing-slips' ) );
326
+ // Displays option description.
327
+ if ( isset( $description ) ) {
328
+ printf( '<p class="description">%s</p>', $description );
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Wrapper function to create tabs for settings in different languages
334
+ * @param [type] $args [description]
335
+ * @param [type] $callback [description]
336
+ * @return [type] [description]
337
+ */
338
+ public function i18n_wrap ( $args ) {
339
+ extract( $this->normalize_settings_args( $args ) );
340
+
341
+ if ( $languages = $this->get_languages() ) {
342
+ printf( '<div id="%s-%s-translations" class="translations">', $option_name, $id)
343
+ ?>
344
+ <ul>
345
+ <?php foreach ( $languages as $lang_code => $language_name ) {
346
+ $translation_id = "{$option_name}_{$id}_{$lang_code}";
347
+ printf('<li><a href="#%s">%s</a></li>', $translation_id, $language_name );
348
+ }
349
+ ?>
350
+ </ul>
351
+ <?php foreach ( $languages as $lang_code => $language_name ) {
352
+ $translation_id = "{$option_name}_{$id}_{$lang_code}";
353
+ printf( '<div id="%s">', $translation_id );
354
+ $args['lang'] = $lang_code;
355
+ // don't use internationalized placeholders since they're not translated,
356
+ // to avoid confusion (user thinking they're all the same)
357
+ if ( $callback == 'multiple_text_input' ) {
358
+ foreach ($fields as $key => $field_args) {
359
+ if (!empty($field_args['placeholder']) && isset($field_args['i18n_placeholder'])) {
360
+ $args['fields'][$key]['placeholder'] = '';
361
+ }
362
+ }
363
+ } else {
364
+ if (!empty($args['placeholder']) && isset($args['i18n_placeholder'])) {
365
+ $args['placeholder'] = '';
366
+ }
367
+ }
368
+ // specific description for internationalized fields (to compensate for missing placeholder)
369
+ if (!empty($args['i18n_description'])) {
370
+ $args['description'] = $args['i18n_description'];
371
+ }
372
+ call_user_func( array( $this, $callback ), $args );
373
+ echo '</div>';
374
+ }
375
+ ?>
376
+
377
+ </div>
378
+ <?php
379
+ } else {
380
+ $args['lang'] = 'default';
381
+ call_user_func( array( $this, $callback ), $args );
382
+ }
383
+ }
384
+
385
+ public function get_languages () {
386
+ $multilingual = function_exists('icl_get_languages');
387
+ // $multilingual = true; // for development
388
+
389
+ if ($multilingual) {
390
+ // use this instead of function call for development outside of WPML
391
+ // $icl_get_languages = 'a:3:{s:2:"en";a:8:{s:2:"id";s:1:"1";s:6:"active";s:1:"1";s:11:"native_name";s:7:"English";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"English";s:13:"language_code";s:2:"en";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/en.png";s:3:"url";s:23:"http://yourdomain/about";}s:2:"fr";a:8:{s:2:"id";s:1:"4";s:6:"active";s:1:"0";s:11:"native_name";s:9:"Français";s:7:"missing";s:1:"0";s:15:"translated_name";s:6:"French";s:13:"language_code";s:2:"fr";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/fr.png";s:3:"url";s:29:"http://yourdomain/fr/a-propos";}s:2:"it";a:8:{s:2:"id";s:2:"27";s:6:"active";s:1:"0";s:11:"native_name";s:8:"Italiano";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"Italian";s:13:"language_code";s:2:"it";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/it.png";s:3:"url";s:26:"http://yourdomain/it/circa";}}';
392
+ // $icl_get_languages = unserialize($icl_get_languages);
393
+
394
+ $icl_get_languages = icl_get_languages('skip_missing=0');
395
+ $languages = array();
396
+ foreach ($icl_get_languages as $lang => $data) {
397
+ $languages[$data['language_code']] = $data['native_name'];
398
+ }
399
+ } else {
400
+ return false;
401
+ }
402
+
403
+ return $languages;
404
+ }
405
+
406
+ public function normalize_settings_args ( $args ) {
407
+ $args['value'] = isset( $args['value'] ) ? $args['value'] : 1;
408
+
409
+ $args['placeholder'] = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
410
+
411
+ // get main settings array
412
+ $option = get_option( $args['option_name'] );
413
+
414
+ $args['setting_name'] = "{$args['option_name']}[{$args['id']}]";
415
+
416
+ if ( !isset($args['lang']) && !empty($args['translatable']) ) {
417
+ $args['lang'] = 'default';
418
+ }
419
+
420
+ if (isset($args['lang'])) {
421
+ // i18n settings name
422
+ $args['setting_name'] = "{$args['setting_name']}[{$args['lang']}]";
423
+ // copy current option value if set
424
+
425
+ if ( $args['lang'] == 'default' && !empty($option[$args['id']]) && !isset( $option[$args['id']]['default'] ) ) {
426
+ // we're switching back from WPML to normal
427
+ // try english first
428
+ if ( isset( $option[$args['id']]['en'] ) ) {
429
+ $args['current'] = $option[$args['id']]['en'];
430
+ } elseif ( is_array( $option[$args['id']] ) ) {
431
+ // fallback to the first language if english not found
432
+ $first = array_shift($option[$args['id']]);
433
+ if (!empty($first)) {
434
+ $args['current'] = $first;
435
+ }
436
+ } elseif ( is_string( $option[$args['id']] ) ) {
437
+ $args['current'] = $option[$args['id']];
438
+ } else {
439
+ // nothing, really?
440
+ $args['current'] = '';
441
+ }
442
+ } else {
443
+ if ( isset( $option[$args['id']][$args['lang']] ) ) {
444
+ $args['current'] = $option[$args['id']][$args['lang']];
445
+ } elseif (isset( $option[$args['id']]['default'] )) {
446
+ $args['current'] = $option[$args['id']]['default'];
447
+ }
448
+ }
449
+ } else {
450
+ // copy current option value if set
451
+ if ( isset( $option[$args['id']] ) ) {
452
+ $args['current'] = $option[$args['id']];
453
+ }
454
+ }
455
+
456
+ // falback to default or empty if no value in option
457
+ if ( !isset($args['current']) ) {
458
+ $args['current'] = isset( $args['default'] ) ? $args['default'] : '';
459
+ }
460
+
461
+ return $args;
462
+ }
463
+
464
+ /**
465
+ * Validate options.
466
+ *
467
+ * @param array $input options to valid.
468
+ *
469
+ * @return array validated options.
470
+ */
471
+ public function validate( $input ) {
472
+ // echo '<pre>';var_dump($input);die('</pre>');
473
+ // Create our array for storing the validated options.
474
+ $output = array();
475
+
476
+ if (empty($input) || !is_array($input)) {
477
+ return $input;
478
+ }
479
+
480
+ // Loop through each of the incoming options.
481
+ foreach ( $input as $key => $value ) {
482
+
483
+ // Check to see if the current option has a value. If so, process it.
484
+ if ( isset( $input[$key] ) ) {
485
+ if ( is_array( $input[$key] ) ) {
486
+ foreach ( $input[$key] as $sub_key => $sub_value ) {
487
+ $output[$key][$sub_key] = $input[$key][$sub_key];
488
+ }
489
+ } else {
490
+ $output[$key] = $input[$key];
491
+ }
492
+ }
493
+ }
494
+
495
+ // Return the array processing any additional functions filtered by this action.
496
+ return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
497
+ }
498
+ }
499
+
500
+
501
+ endif; // class_exists
502
+
 
503
  return new Settings_Callbacks();
includes/views/dompdf-status.php CHANGED
@@ -1,202 +1,203 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) {
3
- exit; // Exit if accessed directly
4
- }
5
-
6
- $memory_limit = function_exists('wc_let_to_num')?wc_let_to_num( WP_MEMORY_LIMIT ):woocommerce_let_to_num( WP_MEMORY_LIMIT );
7
-
8
- $server_configs = array(
9
- "DOMDocument extension" => array(
10
- "required" => true,
11
- "value" => phpversion("DOM"),
12
- "result" => class_exists("DOMDocument"),
13
- ),
14
- "MBString extension" => array(
15
- "required" => true,
16
- "value" => phpversion("mbstring"),
17
- "result" => function_exists("mb_send_mail"),
18
- "fallback" => "Recommended, will use fallback functions",
19
- ),
20
- "GD" => array(
21
- "required" => true,
22
- "value" => phpversion("gd"),
23
- "result" => function_exists("imagecreate"),
24
- "fallback" => "Required if you have images in your documents",
25
- ),
26
- // "PCRE" => array(
27
- // "required" => true,
28
- // "value" => phpversion("pcre"),
29
- // "result" => function_exists("preg_match") && @preg_match("/./u", "a"),
30
- // "failure" => "PCRE is required with Unicode support (the \"u\" modifier)",
31
- // ),
32
- "Zlib" => array(
33
- "required" => "To compress PDF documents",
34
- "value" => phpversion("zlib"),
35
- "result" => function_exists("gzcompress"),
36
- "fallback" => "Recommended to compress PDF documents",
37
- ),
38
- "opcache" => array(
39
- "required" => "For better performances",
40
- "value" => null,
41
- "result" => false,
42
- "fallback" => "Recommended for better performances",
43
- ),
44
- "GMagick or IMagick" => array(
45
- "required" => "Better with transparent PNG images",
46
- "value" => null,
47
- "result" => extension_loaded("gmagick") || extension_loaded("imagick"),
48
- "fallback" => "Recommended for better performances",
49
- ),
50
- "glob()" => array(
51
- "required" => "Required to detect custom templates and to clear the temp folder periodically",
52
- "value" => null,
53
- "result" => function_exists("glob"),
54
- "fallback" => "Check php disable_functions",
55
- ),
56
- "WP Memory Limit" => array(
57
- "required" => 'Recommended: 128MB (more for plugin-heavy setups)<br/>See: <a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">Increasing memory allocated to PHP</a>',
58
- "value" => WP_MEMORY_LIMIT,
59
- "result" => $memory_limit > 67108864,
60
- ),
61
- 'allow_url_fopen' => array (
62
- 'required' => 'Allow remote stylesheets and images',
63
- 'value' => null,
64
- 'result' => ini_get("allow_url_fopen"),
65
- "fallback" => "allow_url_fopen disabled",
66
- ),
67
- );
68
-
69
- if (($xc = extension_loaded("xcache")) || ($apc = extension_loaded("apc")) || ($zop = extension_loaded("Zend OPcache")) || ($op = extension_loaded("opcache"))) {
70
- $server_configs["opcache"]["result"] = true;
71
- $server_configs["opcache"]["value"] = (
72
- $xc ? "XCache ".phpversion("xcache") : (
73
- $apc ? "APC ".phpversion("apc") : (
74
- $zop ? "Zend OPCache ".phpversion("Zend OPcache") : "PHP OPCache ".phpversion("opcache")
75
- )
76
- )
77
- );
78
- }
79
- if (($gm = extension_loaded("gmagick")) || ($im = extension_loaded("imagick"))) {
80
- $server_configs["GMagick or IMagick"]["value"] = ($im ? "IMagick ".phpversion("imagick") : "GMagick ".phpversion("gmagick"));
81
- }
82
-
83
- ?>
84
-
85
- <h3 id="system">System Configuration</h3>
86
-
87
- <table cellspacing="1px" cellpadding="4px" style="background-color: white; padding: 5px; border: 1px solid #ccc;">
88
- <tr>
89
- <th align="left">&nbsp;</th>
90
- <th align="left">Required</th>
91
- <th align="left">Present</th>
92
- </tr>
93
-
94
- <?php foreach($server_configs as $label => $server_config) {
95
- if ($server_config["result"]) {
96
- $background = "#9e4";
97
- $color = "black";
98
- } elseif (isset($server_config["fallback"])) {
99
- $background = "#FCC612";
100
- $color = "black";
101
- } else {
102
- $background = "#f43";
103
- $color = "white";
104
- }
105
- ?>
106
- <tr>
107
- <td class="title"><?php echo $label; ?></td>
108
- <td><?php echo ($server_config["required"] === true ? "Yes" : $server_config["required"]); ?></td>
109
- <td style="background-color:<?php echo $background; ?>; color:<?php echo $color; ?>">
110
- <?php
111
- echo $server_config["value"];
112
- if ($server_config["result"] && !$server_config["value"]) echo "Yes";
113
- if (!$server_config["result"]) {
114
- if (isset($server_config["fallback"])) {
115
- echo "<div>No. ".$server_config["fallback"]."</div>";
116
- }
117
- if (isset($server_config["failure"])) {
118
- echo "<div>".$server_config["failure"]."</div>";
119
- }
120
- }
121
- ?>
122
- </td>
123
- </tr>
124
- <?php } ?>
125
-
126
- </table>
127
-
128
- <?php
129
- $permissions = array(
130
- 'WCPDF_TEMP_DIR' => array (
131
- 'description' => 'Central temporary plugin folder',
132
- 'value' => WPO_WCPDF()->main->get_tmp_path(),
133
- 'status' => (is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? "ok" : "failed"),
134
- 'status_message' => (is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? "Writable" : "Not writable"),
135
- ),
136
- 'WCPDF_ATTACHMENT_DIR' => array (
137
- 'description' => 'Temporary attachments folder',
138
- 'value' => trailingslashit( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ),
139
- 'status' => (is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? "ok" : "failed"),
140
- 'status_message' => (is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? "Writable" : "Not writable"),
141
- ),
142
- 'DOMPDF_TEMP_DIR' => array (
143
- 'description' => 'Temporary DOMPDF folder',
144
- 'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )),
145
- 'status' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? "ok" : "failed"),
146
- 'status_message' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? "Writable" : "Not writable"),
147
- ),
148
- 'DOMPDF_FONT_DIR' => array (
149
- 'description' => 'DOMPDF fonts folder (needs to be writable for custom/remote fonts)',
150
- 'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'fonts' )),
151
- 'status' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? "ok" : "failed"),
152
- 'status_message' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? "Writable" : "Not writable"),
153
- ),
154
- );
155
-
156
- $upload_dir = wp_upload_dir();
157
- $upload_base = trailingslashit( $upload_dir['basedir'] );
158
-
159
- ?>
160
- <br />
161
- <h3 id="system">Write Permissions</h3>
162
- <table cellspacing="1px" cellpadding="4px" style="background-color: white; padding: 5px; border: 1px solid #ccc;">
163
- <tr>
164
- <th align="left">Description</th>
165
- <th align="left">Value</th>
166
- <th align="left">Status</th>
167
- </tr>
168
- <?php
169
- foreach ($permissions as $permission) {
170
- if ($permission['status'] == 'ok') {
171
- $background = "#9e4";
172
- $color = "black";
173
- } else {
174
- $background = "#f43";
175
- $color = "white";
176
- }
177
- ?>
178
- <tr>
179
- <td><?php echo $permission['description']; ?></td>
180
- <td><?php echo $permission['value']; ?></td>
181
- <td style="background-color:<?php echo $background; ?>; color:<?php echo $color; ?>"><?php echo $permission['status_message']; ?></td>
182
- </tr>
183
-
184
- <?php } ?>
185
-
186
- </table>
187
-
188
- <p>
189
- The central temp folder is <code><?php echo WPO_WCPDF()->main->get_tmp_path(); ?></code>.
190
- By default, this folder is created in the WordPress uploads folder (<code><?php echo $upload_base; ?></code>),
191
- which can be defined by setting <code>UPLOADS</code> in wp-config.php.
192
- Alternatively, you can control the specific folder for PDF invoices by using the
193
- <code>wpo_wcpdf_tmp_path</code> filter. Make sure this folder is writable and that the
194
- subfolders <code>attachments</code>, <code>dompdf</code> and <code>fonts</code>
195
- are present (these will be created by the plugin if the central temp folder is writable).<br>
196
- <br>
197
- If the temporary folders were not automatically created by the plugin, verify that all the font
198
- files (from <code><?php echo WPO_WCPDF()->plugin_path() . "/vendor/dompdf/dompdf/lib/fonts/"; ?></code>)
199
- are copied to the fonts folder.
200
- Normally, this is fully automated, but if your server has strict security settings, this automated
201
- copying may have been prohibited. In that case, you also need to make sure these folders get
 
202
  synchronized on plugin updates!
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly
4
+ }
5
+
6
+ $memory_limit = function_exists('wc_let_to_num')?wc_let_to_num( WP_MEMORY_LIMIT ):woocommerce_let_to_num( WP_MEMORY_LIMIT );
7
+ $php_mem_limit = function_exists( 'memory_get_usage' ) ? @ini_get( 'memory_limit' ) : '-';
8
+
9
+ $server_configs = array(
10
+ "DOMDocument extension" => array(
11
+ "required" => true,
12
+ "value" => phpversion("DOM"),
13
+ "result" => class_exists("DOMDocument"),
14
+ ),
15
+ "MBString extension" => array(
16
+ "required" => true,
17
+ "value" => phpversion("mbstring"),
18
+ "result" => function_exists("mb_send_mail"),
19
+ "fallback" => "Recommended, will use fallback functions",
20
+ ),
21
+ "GD" => array(
22
+ "required" => true,
23
+ "value" => phpversion("gd"),
24
+ "result" => function_exists("imagecreate"),
25
+ "fallback" => "Required if you have images in your documents",
26
+ ),
27
+ // "PCRE" => array(
28
+ // "required" => true,
29
+ // "value" => phpversion("pcre"),
30
+ // "result" => function_exists("preg_match") && @preg_match("/./u", "a"),
31
+ // "failure" => "PCRE is required with Unicode support (the \"u\" modifier)",
32
+ // ),
33
+ "Zlib" => array(
34
+ "required" => "To compress PDF documents",
35
+ "value" => phpversion("zlib"),
36
+ "result" => function_exists("gzcompress"),
37
+ "fallback" => "Recommended to compress PDF documents",
38
+ ),
39
+ "opcache" => array(
40
+ "required" => "For better performances",
41
+ "value" => null,
42
+ "result" => false,
43
+ "fallback" => "Recommended for better performances",
44
+ ),
45
+ "GMagick or IMagick" => array(
46
+ "required" => "Better with transparent PNG images",
47
+ "value" => null,
48
+ "result" => extension_loaded("gmagick") || extension_loaded("imagick"),
49
+ "fallback" => "Recommended for better performances",
50
+ ),
51
+ "glob()" => array(
52
+ "required" => "Required to detect custom templates and to clear the temp folder periodically",
53
+ "value" => null,
54
+ "result" => function_exists("glob"),
55
+ "fallback" => "Check php disable_functions",
56
+ ),
57
+ "WP Memory Limit" => array(
58
+ "required" => 'Recommended: 128MB (more for plugin-heavy setups)<br/>See: <a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">Increasing memory allocated to PHP</a>',
59
+ "value" => sprintf("WordPress: %s, PHP: %s", WP_MEMORY_LIMIT, $php_mem_limit ),
60
+ "result" => $memory_limit > 67108864,
61
+ ),
62
+ 'allow_url_fopen' => array (
63
+ 'required' => 'Allow remote stylesheets and images',
64
+ 'value' => null,
65
+ 'result' => ini_get("allow_url_fopen"),
66
+ "fallback" => "allow_url_fopen disabled",
67
+ ),
68
+ );
69
+
70
+ if (($xc = extension_loaded("xcache")) || ($apc = extension_loaded("apc")) || ($zop = extension_loaded("Zend OPcache")) || ($op = extension_loaded("opcache"))) {
71
+ $server_configs["opcache"]["result"] = true;
72
+ $server_configs["opcache"]["value"] = (
73
+ $xc ? "XCache ".phpversion("xcache") : (
74
+ $apc ? "APC ".phpversion("apc") : (
75
+ $zop ? "Zend OPCache ".phpversion("Zend OPcache") : "PHP OPCache ".phpversion("opcache")
76
+ )
77
+ )
78
+ );
79
+ }
80
+ if (($gm = extension_loaded("gmagick")) || ($im = extension_loaded("imagick"))) {
81
+ $server_configs["GMagick or IMagick"]["value"] = ($im ? "IMagick ".phpversion("imagick") : "GMagick ".phpversion("gmagick"));
82
+ }
83
+
84
+ ?>
85
+
86
+ <h3 id="system">System Configuration</h3>
87
+
88
+ <table cellspacing="1px" cellpadding="4px" style="background-color: white; padding: 5px; border: 1px solid #ccc;">
89
+ <tr>
90
+ <th align="left">&nbsp;</th>
91
+ <th align="left">Required</th>
92
+ <th align="left">Present</th>
93
+ </tr>
94
+
95
+ <?php foreach($server_configs as $label => $server_config) {
96
+ if ($server_config["result"]) {
97
+ $background = "#9e4";
98
+ $color = "black";
99
+ } elseif (isset($server_config["fallback"])) {
100
+ $background = "#FCC612";
101
+ $color = "black";
102
+ } else {
103
+ $background = "#f43";
104
+ $color = "white";
105
+ }
106
+ ?>
107
+ <tr>
108
+ <td class="title"><?php echo $label; ?></td>
109
+ <td><?php echo ($server_config["required"] === true ? "Yes" : $server_config["required"]); ?></td>
110
+ <td style="background-color:<?php echo $background; ?>; color:<?php echo $color; ?>">
111
+ <?php
112
+ echo $server_config["value"];
113
+ if ($server_config["result"] && !$server_config["value"]) echo "Yes";
114
+ if (!$server_config["result"]) {
115
+ if (isset($server_config["fallback"])) {
116
+ echo "<div>No. ".$server_config["fallback"]."</div>";
117
+ }
118
+ if (isset($server_config["failure"])) {
119
+ echo "<div>".$server_config["failure"]."</div>";
120
+ }
121
+ }
122
+ ?>
123
+ </td>
124
+ </tr>
125
+ <?php } ?>
126
+
127
+ </table>
128
+
129
+ <?php
130
+ $permissions = array(
131
+ 'WCPDF_TEMP_DIR' => array (
132
+ 'description' => 'Central temporary plugin folder',
133
+ 'value' => WPO_WCPDF()->main->get_tmp_path(),
134
+ 'status' => (is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? "ok" : "failed"),
135
+ 'status_message' => (is_writable( WPO_WCPDF()->main->get_tmp_path() ) ? "Writable" : "Not writable"),
136
+ ),
137
+ 'WCPDF_ATTACHMENT_DIR' => array (
138
+ 'description' => 'Temporary attachments folder',
139
+ 'value' => trailingslashit( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ),
140
+ 'status' => (is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? "ok" : "failed"),
141
+ 'status_message' => (is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? "Writable" : "Not writable"),
142
+ ),
143
+ 'DOMPDF_TEMP_DIR' => array (
144
+ 'description' => 'Temporary DOMPDF folder',
145
+ 'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )),
146
+ 'status' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? "ok" : "failed"),
147
+ 'status_message' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'dompdf' )) ? "Writable" : "Not writable"),
148
+ ),
149
+ 'DOMPDF_FONT_DIR' => array (
150
+ 'description' => 'DOMPDF fonts folder (needs to be writable for custom/remote fonts)',
151
+ 'value' => trailingslashit(WPO_WCPDF()->main->get_tmp_path( 'fonts' )),
152
+ 'status' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? "ok" : "failed"),
153
+ 'status_message' => (is_writable(WPO_WCPDF()->main->get_tmp_path( 'fonts' )) ? "Writable" : "Not writable"),
154
+ ),
155
+ );
156
+
157
+ $upload_dir = wp_upload_dir();
158
+ $upload_base = trailingslashit( $upload_dir['basedir'] );
159
+
160
+ ?>
161
+ <br />
162
+ <h3 id="system">Write Permissions</h3>
163
+ <table cellspacing="1px" cellpadding="4px" style="background-color: white; padding: 5px; border: 1px solid #ccc;">
164
+ <tr>
165
+ <th align="left">Description</th>
166
+ <th align="left">Value</th>
167
+ <th align="left">Status</th>
168
+ </tr>
169
+ <?php
170
+ foreach ($permissions as $permission) {
171
+ if ($permission['status'] == 'ok') {
172
+ $background = "#9e4";
173
+ $color = "black";
174
+ } else {
175
+ $background = "#f43";
176
+ $color = "white";
177
+ }
178
+ ?>
179
+ <tr>
180
+ <td><?php echo $permission['description']; ?></td>
181
+ <td><?php echo $permission['value']; ?></td>
182
+ <td style="background-color:<?php echo $background; ?>; color:<?php echo $color; ?>"><?php echo $permission['status_message']; ?></td>
183
+ </tr>
184
+
185
+ <?php } ?>
186
+
187
+ </table>
188
+
189
+ <p>
190
+ The central temp folder is <code><?php echo WPO_WCPDF()->main->get_tmp_path(); ?></code>.
191
+ By default, this folder is created in the WordPress uploads folder (<code><?php echo $upload_base; ?></code>),
192
+ which can be defined by setting <code>UPLOADS</code> in wp-config.php.
193
+ Alternatively, you can control the specific folder for PDF invoices by using the
194
+ <code>wpo_wcpdf_tmp_path</code> filter. Make sure this folder is writable and that the
195
+ subfolders <code>attachments</code>, <code>dompdf</code> and <code>fonts</code>
196
+ are present (these will be created by the plugin if the central temp folder is writable).<br>
197
+ <br>
198
+ If the temporary folders were not automatically created by the plugin, verify that all the font
199
+ files (from <code><?php echo WPO_WCPDF()->plugin_path() . "/vendor/dompdf/dompdf/lib/fonts/"; ?></code>)
200
+ are copied to the fonts folder.
201
+ Normally, this is fully automated, but if your server has strict security settings, this automated
202
+ copying may have been prohibited. In that case, you also need to make sure these folders get
203
  synchronized on plugin updates!
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-
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: 4.8
7
- Stable tag: 2.0.10
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -104,6 +104,11 @@ There's a setting on the Status tab of the settings page that allows you to togg
104
 
105
  **2.0 is a BIG update! Make a full site backup before upgrading**
106
 
 
 
 
 
 
107
  = 2.0.10 =
108
  * Fix: Set invoice number backend button
109
  * Fix: Thumbail paths
@@ -184,5 +189,5 @@ There's a setting on the Status tab of the settings page that allows you to togg
184
 
185
  == Upgrade Notice ==
186
 
187
- = 2.0.10 =
188
  **2.0 is a BIG update! Make a full site backup before upgrading!**
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: 4.8
7
+ Stable tag: 2.0.11
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
104
 
105
  **2.0 is a BIG update! Make a full site backup before upgrading**
106
 
107
+ = 2.0.11 =
108
+ * Fix: Improved fonts update routine (now preserves custom fonts)
109
+ * Fix: Enable HTML5 parser by default (fixes issues with libxml)
110
+ * Tweak: Show both PHP & WP Memory limit in Status tab
111
+
112
  = 2.0.10 =
113
  * Fix: Set invoice number backend button
114
  * Fix: Thumbail paths
189
 
190
  == Upgrade Notice ==
191
 
192
+ = 2.0.11 =
193
  **2.0 is a BIG update! Make a full site backup before upgrading!**
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 2.0.10
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
@@ -19,7 +19,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
19
 
20
  class WPO_WCPDF {
21
 
22
- public $version = '2.0.10';
23
  public $plugin_basename;
24
  public $legacy_mode;
25
 
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 2.0.11
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
19
 
20
  class WPO_WCPDF {
21
 
22
+ public $version = '2.0.11';
23
  public $plugin_basename;
24
  public $legacy_mode;
25