WooCommerce Germanized - Version 2.3.1

Version Description

  • Feature: Added better fee/shipping costs calculation to order tax recalculation
  • Feature: Grouped products: Unit price support if all children share the same unit
  • Feature: Grouped products: Show legal info per item
  • Improvement: Activate parcel shop delivery address format as soon as post number is added to the order
  • Improvement: Force customer registration redirect for customer that have not yet been activated (DOI)
  • Improvement: Added _legal_text post meta to wpml config
  • Tweak: Do not watch for product updates within checkout (causes problem with WPML)
Download this release

Release Info

Developer vendidero
Plugin Icon 128x128 WooCommerce Germanized
Version 2.3.1
Comparing to
See all releases

Code changes from version 2.3.0 to 2.3.1

assets/css/woocommerce-gzd-admin.css CHANGED
@@ -373,4 +373,10 @@ table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-sort::before {
373
  color: transparent;
374
  box-shadow: none;
375
  border: none;
 
 
 
 
 
 
376
  }
373
  color: transparent;
374
  box-shadow: none;
375
  border: none;
376
+ }
377
+
378
+ .parcel-delivery-checkbox-status {
379
+ float: left;
380
+ width: 100%;
381
+ clear: both;
382
  }
assets/css/woocommerce-gzd-admin.min.css CHANGED
@@ -1 +1 @@
1
- .wc-gzd-button,.wc-gzd-button:hover{box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15)!important}.wc-gzd-admin-settings-agbs,.wc-gzd-admin-settings-sidebar img,.wc-gzd-admin-settings-widerruf{width:100%}.wc-gzd-pro:hover,.wc-gzd-pro:visited{color:#FFF}.wc-gzd-admin-settings tr.single_select_page .description{margin-top:.5em}.wc-gzd-admin-settings .wc-gzd-label-wrap{position:relative;display:block;vertical-align:middle}.wc-gzd-admin-settings .wc-gzd-label-wrap .woocommerce-help-tip{margin:-8px -24px 0 0!important;position:absolute;right:0;top:50%}.wc-gzd-admin-settings a.woocommerce-gzd-input-toggle-trigger{color:transparent;border:none;text-decoration:none}.wc-gzd-admin-settings a.woocommerce-gzd-input-toggle-trigger:focus{color:transparent;box-shadow:none;border:none}.wc-gzd-resend-activation-link{margin-top:1em!important}.wc-gzd-unit-price-disabled-notice{margin:1em 0!important;box-sizing:border-box;display:none;padding:5px 12px}table.wc-gzd-legal-checkboxes thead th{vertical-align:middle}table.wc-gzd-legal-checkboxes thead th.wc-gzd-legal-checkbox-sort{text-align:center}table.wc-gzd-legal-checkboxes td,table.wc-gzd-legal-checkboxes th{vertical-align:top;line-height:24px;padding:1em!important;font-size:14px;background:#fff;display:table-cell!important}table.wc-gzd-legal-checkboxes td ul{margin:0}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-locations ul li::before{content:', '}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-locations ul li:first-child::before{content:''}table.wc-gzd-legal-checkboxes td .status-disabled,table.wc-gzd-legal-checkboxes td .status-enabled{margin-top:3px}table.wc-gzd-legal-checkboxes td ul li{line-height:24px;font-size:14px;color:#555;display:inline;margin:0}table.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows td{border-top:2px solid #f9f9f9}table.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows tr:first-child td{border-top:0}.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows tr:nth-child( odd ) td{background:#f9f9f9}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-sort::before{content:'\f333';font-family:Dashicons;text-align:center;color:#999;display:block;width:17px;float:left;height:100%;line-height:24px}.wc-gzd-admin-settings-checkboxes td.forminp-textarea p code{margin:.5em 0;display:block}.wc-gzd-admin-settings-checkboxes td.forminp-textarea p{margin-bottom:1em}.wc-gzd-admin-settings-checkboxes td.forminp-textarea .gzd-small-desc{font-size:12px;font-style:italic}.wc-gzd-admin-settings-checkboxes td.forminp-text .description{margin-top:.5em;line-height:1.5em;display:block}.wc-gzd-button{background-color:#7b9f35!important}.wc-gzd-button:hover{background-color:#73982a!important}.wc-action-button-xml:after{content:"\f475"}#gzd-admin-sepa{padding-top:1em;display:block;clear:both;width:100%}#order_data .order_data_column a.download_sepa_xml{width:14px;height:0;padding:14px 0 0;margin:0 0 0 6px;overflow:hidden;position:relative;color:#999;border:0;float:right}#order_data .order_data_column a.download_sepa_xml::after{font-family:Dashicons;content:'\f546';position:absolute;top:0;left:0;text-align:center;vertical-align:top;line-height:14px;font-size:14px;font-weight:400;-webkit-font-smoothing:antialiased}#order_data .order_data_column ._direct_debit_bic_field,#order_data .order_data_column ._direct_debit_holder_field,#order_data .order_data_column ._direct_debit_iban_field,#order_data .order_data_column ._direct_debit_mandate_id_field{clear:left;width:100%!important}#order_data .order_data_column ._direct_debit_bic_field input,#order_data .order_data_column ._direct_debit_holder_field input,#order_data .order_data_column ._direct_debit_iban_field input,#order_data .order_data_column ._direct_debit_mandate_id_field input{width:100%}.wc-gzd-button,.wc-gzd-button:hover{border:1px solid #557020!important;text-shadow:none!important}.wc-gzd-admin-settings tr.single_select_page .description{display:block}.wc-gzd-admin-settings td.forminp-select .description{position:relative;top:3px;margin-left:10px}#order_data ._shipping_parcelshop_post_number_field{clear:left;width:100%!important}table.form-table .forminp-radio fieldset p{margin-bottom:1em}p._unit_price_auto_field label{display:block!important;margin-bottom:5px}.woocommerce-gzd-message ul{margin-left:20px}.woocommerce-gzd-message ul li{list-style:disc}.wc-gzd-admin-settings,.wc-gzd-admin-settings-sidebar{display:inline-block;box-sizing:border-box;vertical-align:top}table.data_table tr td p.form-field{margin:0!important;padding:0!important}.variable_cart_mini_desc .wp-editor-tools{margin-top:-3em}.variable_cart_mini_desc_pre .wp-editor-tools{margin-top:-2em}.wc-gzd-admin-settings{width:70%;border-right:1px solid #CCC;padding-right:2%}.wc-gzd-admin-settings-sidebar{padding-left:2%;margin-left:-4px;width:30%}.wc-gzd-admin-settings-sidebar .browser{border:1px solid #CCC;border-radius:3px}.wc-gzd-admin-settings-sidebar .small{font-size:.9em;display:block;margin-top:.5em}._billing_address_1_field,._billing_title_field,._shipping_address_1_field,._shipping_title_field{width:100%!important}.wc-gzd-button-wrapper .button{margin-right:1em}.wc-gzd-premium-section-tab,.wc-gzd-pro{font-size:9px;background:#0074a2;border-radius:3px;line-height:9px;color:#FFF;text-align:center;text-transform:uppercase;padding:1px 3px;position:relative;top:-1px}.wc-gzd-premium-section-tab{background:#e4e4e4;border:1px solid #CCC;color:#555;padding:0 3px}.wc-gzd-pro{background:#222;font-style:normal;opacity:1!important;text-decoration:none}.tourbus-leg-inner .wc-gzd-pro{top:-3px}.forminp-image img,.wc-gzd-premium img{width:100%;height:auto;opacity:.7}.woocommerce table.form-table th.forminp-image{padding-right:0}._unit_price_auto_field .wc-gzd-premium-desc,._unit_price_auto_field input,._unit_price_auto_field label{opacity:.6}table.wc-gzd-tax-example tr td,table.wc-gzd-tax-example tr th{padding:5px;font-size:.9em}table.wc-gzd-tax-example tr td:first-child,table.wc-gzd-tax-example tr th:first-child{padding-left:0}.wc-gzd-admin-settings tbody.ui-sortable tr:hover{cursor:move}#order_data .order_data_column ._direct_debit_bic_field,#order_data .order_data_column ._direct_debit_holder_field,#order_data .order_data_column ._direct_debit_iban_field,#order_data .order_data_column ._direct_debit_reference_field{clear:left;width:100%!important}#order_data .order_data_column ._direct_debit_bic_field input,#order_data .order_data_column ._direct_debit_holder_field input,#order_data .order_data_column ._direct_debit_iban_field input,#order_data .order_data_column ._direct_debit_reference_field input{width:100%}.wc-gzd-text-red{color:red}.wc-gzd-status-text{font-weight:600}.wc-gzd-text-green{color:green}.order_actions .xml{display:block;text-indent:-9999px;position:relative;padding:0!important;height:2em!important;width:2em}.order_actions .xml:after{content:"\e00d";font-family:WooCommerce;text-indent:0;position:absolute;width:100%;height:100%;speak:none;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;top:0;left:0;line-height:1.85;margin:0;text-align:center;font-weight:400}
1
+ .wc-gzd-button,.wc-gzd-button:hover{box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 rgba(0,0,0,.15)!important}.wc-gzd-admin-settings-agbs,.wc-gzd-admin-settings-sidebar img,.wc-gzd-admin-settings-widerruf{width:100%}.wc-gzd-pro:hover,.wc-gzd-pro:visited{color:#FFF}.wc-gzd-admin-settings tr.single_select_page .description{margin-top:.5em}.parcel-delivery-checkbox-status{float:left;width:100%;clear:both}.wc-gzd-admin-settings .wc-gzd-label-wrap{position:relative;display:block;vertical-align:middle}.wc-gzd-admin-settings .wc-gzd-label-wrap .woocommerce-help-tip{margin:-8px -24px 0 0!important;position:absolute;right:0;top:50%}.wc-gzd-admin-settings a.woocommerce-gzd-input-toggle-trigger{color:transparent;border:none;text-decoration:none}.wc-gzd-admin-settings a.woocommerce-gzd-input-toggle-trigger:focus{color:transparent;box-shadow:none;border:none}.wc-gzd-resend-activation-link{margin-top:1em!important}.wc-gzd-unit-price-disabled-notice{margin:1em 0!important;box-sizing:border-box;display:none;padding:5px 12px}table.wc-gzd-legal-checkboxes thead th{vertical-align:middle}table.wc-gzd-legal-checkboxes thead th.wc-gzd-legal-checkbox-sort{text-align:center}table.wc-gzd-legal-checkboxes td,table.wc-gzd-legal-checkboxes th{vertical-align:top;line-height:24px;padding:1em!important;font-size:14px;background:#fff;display:table-cell!important}table.wc-gzd-legal-checkboxes td ul{margin:0}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-locations ul li::before{content:', '}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-locations ul li:first-child::before{content:''}table.wc-gzd-legal-checkboxes td .status-disabled,table.wc-gzd-legal-checkboxes td .status-enabled{margin-top:3px}table.wc-gzd-legal-checkboxes td ul li{line-height:24px;font-size:14px;color:#555;display:inline;margin:0}table.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows td{border-top:2px solid #f9f9f9}table.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows tr:first-child td{border-top:0}.wc-gzd-legal-checkboxes tbody.wc-gzd-legal-checkbox-rows tr:nth-child( odd ) td{background:#f9f9f9}table.wc-gzd-legal-checkboxes td.wc-gzd-legal-checkbox-sort::before{content:'\f333';font-family:Dashicons;text-align:center;color:#999;display:block;width:17px;float:left;height:100%;line-height:24px}.wc-gzd-admin-settings-checkboxes td.forminp-textarea p code{margin:.5em 0;display:block}.wc-gzd-admin-settings-checkboxes td.forminp-textarea p{margin-bottom:1em}.wc-gzd-admin-settings-checkboxes td.forminp-textarea .gzd-small-desc{font-size:12px;font-style:italic}.wc-gzd-admin-settings-checkboxes td.forminp-text .description{margin-top:.5em;line-height:1.5em;display:block}.wc-gzd-button{background-color:#7b9f35!important}.wc-gzd-button:hover{background-color:#73982a!important}.wc-action-button-xml:after{content:"\f475"}#gzd-admin-sepa{padding-top:1em;display:block;clear:both;width:100%}#order_data .order_data_column a.download_sepa_xml{width:14px;height:0;padding:14px 0 0;margin:0 0 0 6px;overflow:hidden;position:relative;color:#999;border:0;float:right}#order_data .order_data_column a.download_sepa_xml::after{font-family:Dashicons;content:'\f546';position:absolute;top:0;left:0;text-align:center;vertical-align:top;line-height:14px;font-size:14px;font-weight:400;-webkit-font-smoothing:antialiased}#order_data .order_data_column ._direct_debit_bic_field,#order_data .order_data_column ._direct_debit_holder_field,#order_data .order_data_column ._direct_debit_iban_field,#order_data .order_data_column ._direct_debit_mandate_id_field{clear:left;width:100%!important}#order_data .order_data_column ._direct_debit_bic_field input,#order_data .order_data_column ._direct_debit_holder_field input,#order_data .order_data_column ._direct_debit_iban_field input,#order_data .order_data_column ._direct_debit_mandate_id_field input{width:100%}.wc-gzd-button,.wc-gzd-button:hover{border:1px solid #557020!important;text-shadow:none!important}.wc-gzd-admin-settings tr.single_select_page .description{display:block}.wc-gzd-admin-settings td.forminp-select .description{position:relative;top:3px;margin-left:10px}#order_data ._shipping_parcelshop_post_number_field{clear:left;width:100%!important}table.form-table .forminp-radio fieldset p{margin-bottom:1em}p._unit_price_auto_field label{display:block!important;margin-bottom:5px}.woocommerce-gzd-message ul{margin-left:20px}.woocommerce-gzd-message ul li{list-style:disc}.wc-gzd-admin-settings,.wc-gzd-admin-settings-sidebar{display:inline-block;box-sizing:border-box;vertical-align:top}table.data_table tr td p.form-field{margin:0!important;padding:0!important}.variable_cart_mini_desc .wp-editor-tools{margin-top:-3em}.variable_cart_mini_desc_pre .wp-editor-tools{margin-top:-2em}.wc-gzd-admin-settings{width:70%;border-right:1px solid #CCC;padding-right:2%}.wc-gzd-admin-settings-sidebar{padding-left:2%;margin-left:-4px;width:30%}.wc-gzd-admin-settings-sidebar .browser{border:1px solid #CCC;border-radius:3px}.wc-gzd-admin-settings-sidebar .small{font-size:.9em;display:block;margin-top:.5em}._billing_address_1_field,._billing_title_field,._shipping_address_1_field,._shipping_title_field{width:100%!important}.wc-gzd-button-wrapper .button{margin-right:1em}.wc-gzd-premium-section-tab,.wc-gzd-pro{font-size:9px;background:#0074a2;border-radius:3px;line-height:9px;color:#FFF;text-align:center;text-transform:uppercase;padding:1px 3px;position:relative;top:-1px}.wc-gzd-premium-section-tab{background:#e4e4e4;border:1px solid #CCC;color:#555;padding:0 3px}.wc-gzd-pro{background:#222;font-style:normal;opacity:1!important;text-decoration:none}.tourbus-leg-inner .wc-gzd-pro{top:-3px}.forminp-image img,.wc-gzd-premium img{width:100%;height:auto;opacity:.7}.woocommerce table.form-table th.forminp-image{padding-right:0}._unit_price_auto_field .wc-gzd-premium-desc,._unit_price_auto_field input,._unit_price_auto_field label{opacity:.6}table.wc-gzd-tax-example tr td,table.wc-gzd-tax-example tr th{padding:5px;font-size:.9em}table.wc-gzd-tax-example tr td:first-child,table.wc-gzd-tax-example tr th:first-child{padding-left:0}.wc-gzd-admin-settings tbody.ui-sortable tr:hover{cursor:move}#order_data .order_data_column ._direct_debit_bic_field,#order_data .order_data_column ._direct_debit_holder_field,#order_data .order_data_column ._direct_debit_iban_field,#order_data .order_data_column ._direct_debit_reference_field{clear:left;width:100%!important}#order_data .order_data_column ._direct_debit_bic_field input,#order_data .order_data_column ._direct_debit_holder_field input,#order_data .order_data_column ._direct_debit_iban_field input,#order_data .order_data_column ._direct_debit_reference_field input{width:100%}.wc-gzd-text-red{color:red}.wc-gzd-status-text{font-weight:600}.wc-gzd-text-green{color:green}.order_actions .xml{display:block;text-indent:-9999px;position:relative;padding:0!important;height:2em!important;width:2em}.order_actions .xml:after{content:"\e00d";font-family:WooCommerce;text-indent:0;position:absolute;width:100%;height:100%;speak:none;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;top:0;left:0;line-height:1.85;margin:0;text-align:center;font-weight:400}
includes/abstracts/abstract-wc-gzd-product.php CHANGED
@@ -47,8 +47,9 @@ class WC_GZD_Product {
47
  */
48
  public function __construct( $product ) {
49
 
50
- if ( is_numeric( $product ) )
51
  $product = WC()->product_factory->get_product_standalone( get_post( $product ) );
 
52
 
53
  $this->child = $product;
54
  }
@@ -124,35 +125,19 @@ class WC_GZD_Product {
124
  }
125
 
126
  public function recalculate_unit_price( $args = array() ) {
 
127
 
128
- $args = wp_parse_args( $args, array(
129
- 'regular_price' => $this->get_regular_price(),
130
- 'sale_price' => $this->get_sale_price(),
131
- 'price' => $this->get_price(),
132
- ) );
133
-
134
- $base = $this->unit_base;
135
- $product_base = $base;
136
-
137
- if ( empty( $this->unit_product ) ) {
138
- // Set base multiplicator to 1
139
- $base = 1;
140
- } else {
141
- $product_base = $this->unit_product;
142
- }
143
-
144
- // Do not recalculate if unit base and/or product is empty
145
- if ( 0 == $product_base || 0 == $base )
146
- return;
147
-
148
- $this->unit_price_regular = wc_format_decimal( ( $args[ 'regular_price' ] / $product_base ) * $base, wc_get_price_decimals() );
149
- $this->unit_price_sale = '';
150
 
151
- if ( ! empty( $args[ 'sale_price' ] ) ) {
152
- $this->unit_price_sale = wc_format_decimal( ( $args[ 'sale_price' ] / $product_base ) * $base, wc_get_price_decimals() );
153
- }
154
 
155
- $this->unit_price = wc_format_decimal( ( $args[ 'price' ] / $product_base ) * $base, wc_get_price_decimals() );
 
 
156
 
157
  do_action( 'woocommerce_gzd_recalculated_unit_price', $this );
158
  }
@@ -351,7 +336,6 @@ class WC_GZD_Product {
351
  * @return mixed string if is taxable else returns false
352
  */
353
  public function get_tax_info() {
354
-
355
  $tax_notice = false;
356
  $is_vat_exempt = ( ! empty( WC()->customer ) ? WC()->customer->is_vat_exempt() : false );
357
 
@@ -365,10 +349,11 @@ class WC_GZD_Product {
365
  $tax_rates = array_values( $tax_rates );
366
 
367
  // If is variable or is virtual vat exception dont show exact tax rate
368
- if ( $this->is_virtual_vat_exception() || $this->is_type( 'variable' ) || get_option( 'woocommerce_gzd_hide_tax_rate_shop' ) === 'yes' )
369
  $tax_notice = ( $tax_display_mode == 'incl' && ! $is_vat_exempt ? __( 'incl. VAT', 'woocommerce-germanized' ) : __( 'excl. VAT', 'woocommerce-germanized' ) );
370
- else
371
  $tax_notice = ( $tax_display_mode == 'incl' && ! $is_vat_exempt ? sprintf( __( 'incl. %s%% VAT', 'woocommerce-germanized' ), ( wc_gzd_format_tax_rate_percentage( $tax_rates[0][ 'rate' ] ) ) ) : sprintf( __( 'excl. %s%% VAT', 'woocommerce-germanized' ), ( wc_gzd_format_tax_rate_percentage( $tax_rates[0]['rate'] ) ) ) );
 
372
  }
373
 
374
  if ( $this->is_differential_taxed() ) {
@@ -419,6 +404,10 @@ class WC_GZD_Product {
419
  return false;
420
  }
421
 
 
 
 
 
422
  /**
423
  * Returns unit
424
  *
@@ -426,6 +415,7 @@ class WC_GZD_Product {
426
  */
427
  public function get_unit() {
428
  $unit = $this->unit;
 
429
  return WC_germanized()->units->$unit;
430
  }
431
 
@@ -602,6 +592,7 @@ class WC_GZD_Product {
602
 
603
  public function has_product_units() {
604
  $products = $this->get_unit_products();
 
605
  return ( $products && ! empty( $products ) && $this->get_unit() );
606
  }
607
 
@@ -612,8 +603,9 @@ class WC_GZD_Product {
612
  */
613
  public function get_product_units_html() {
614
 
615
- if ( apply_filters( 'woocommerce_gzd_hide_product_units_text', false, $this ) )
616
  return apply_filters( 'woocommerce_germanized_disabled_product_units_text', '', $this );
 
617
 
618
  $html = '';
619
  $text = get_option( 'woocommerce_gzd_product_units_text' );
@@ -638,21 +630,22 @@ class WC_GZD_Product {
638
  * @return bool|object false returns false if term does not exist otherwise returns term object
639
  */
640
  public function get_delivery_time() {
641
-
642
  $terms = get_the_terms( wc_gzd_get_crud_data( $this->child, 'id' ), 'product_delivery_time' );
643
 
644
  if ( empty( $terms ) && $this->child->is_type( 'variation' ) ) {
645
 
646
  $parent_terms = get_the_terms( wc_gzd_get_crud_data( $this->child, 'parent' ), 'product_delivery_time' );
647
 
648
- if ( ! empty( $parent_terms ) && ! is_wp_error( $parent_terms ) )
649
  $terms = $parent_terms;
 
650
  }
651
 
652
- if ( is_wp_error( $terms ) || empty( $terms ) )
653
  return false;
 
654
 
655
- return $terms[ 0 ];
656
  }
657
 
658
  /**
@@ -700,7 +693,12 @@ class WC_GZD_Product {
700
  '{delivery_time}' => $html,
701
  );
702
 
703
- $html = apply_filters( 'woocommerce_germanized_delivery_time_html', wc_gzd_replace_label_shortcodes( get_option( 'woocommerce_gzd_delivery_time_text' ), $replacements ), get_option( 'woocommerce_gzd_delivery_time_text' ), $html, $this );
 
 
 
 
 
704
  } else {
705
  $html = '';
706
  }
47
  */
48
  public function __construct( $product ) {
49
 
50
+ if ( is_numeric( $product ) ) {
51
  $product = WC()->product_factory->get_product_standalone( get_post( $product ) );
52
+ }
53
 
54
  $this->child = $product;
55
  }
125
  }
126
 
127
  public function recalculate_unit_price( $args = array() ) {
128
+ $prices = wc_gzd_recalculate_unit_price( $args, $this );
129
 
130
+ if ( empty( $prices ) ) {
131
+ return;
132
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
+ if ( isset( $args['base'] ) && ! empty( $args['base'] ) ) {
135
+ $this->unit_base = $args['base'];
136
+ }
137
 
138
+ $this->unit_price_regular = $prices['regular'];
139
+ $this->unit_price_sale = $prices['sale'];
140
+ $this->unit_price = $prices['unit'];
141
 
142
  do_action( 'woocommerce_gzd_recalculated_unit_price', $this );
143
  }
336
  * @return mixed string if is taxable else returns false
337
  */
338
  public function get_tax_info() {
 
339
  $tax_notice = false;
340
  $is_vat_exempt = ( ! empty( WC()->customer ) ? WC()->customer->is_vat_exempt() : false );
341
 
349
  $tax_rates = array_values( $tax_rates );
350
 
351
  // If is variable or is virtual vat exception dont show exact tax rate
352
+ if ( $this->is_virtual_vat_exception() || $this->is_type( 'variable' ) || $this->is_type( 'grouped' ) || get_option( 'woocommerce_gzd_hide_tax_rate_shop' ) === 'yes' ) {
353
  $tax_notice = ( $tax_display_mode == 'incl' && ! $is_vat_exempt ? __( 'incl. VAT', 'woocommerce-germanized' ) : __( 'excl. VAT', 'woocommerce-germanized' ) );
354
+ } else {
355
  $tax_notice = ( $tax_display_mode == 'incl' && ! $is_vat_exempt ? sprintf( __( 'incl. %s%% VAT', 'woocommerce-germanized' ), ( wc_gzd_format_tax_rate_percentage( $tax_rates[0][ 'rate' ] ) ) ) : sprintf( __( 'excl. %s%% VAT', 'woocommerce-germanized' ), ( wc_gzd_format_tax_rate_percentage( $tax_rates[0]['rate'] ) ) ) );
356
+ }
357
  }
358
 
359
  if ( $this->is_differential_taxed() ) {
404
  return false;
405
  }
406
 
407
+ public function get_unit_raw() {
408
+ return $this->unit;
409
+ }
410
+
411
  /**
412
  * Returns unit
413
  *
415
  */
416
  public function get_unit() {
417
  $unit = $this->unit;
418
+
419
  return WC_germanized()->units->$unit;
420
  }
421
 
592
 
593
  public function has_product_units() {
594
  $products = $this->get_unit_products();
595
+
596
  return ( $products && ! empty( $products ) && $this->get_unit() );
597
  }
598
 
603
  */
604
  public function get_product_units_html() {
605
 
606
+ if ( apply_filters( 'woocommerce_gzd_hide_product_units_text', false, $this ) ) {
607
  return apply_filters( 'woocommerce_germanized_disabled_product_units_text', '', $this );
608
+ }
609
 
610
  $html = '';
611
  $text = get_option( 'woocommerce_gzd_product_units_text' );
630
  * @return bool|object false returns false if term does not exist otherwise returns term object
631
  */
632
  public function get_delivery_time() {
 
633
  $terms = get_the_terms( wc_gzd_get_crud_data( $this->child, 'id' ), 'product_delivery_time' );
634
 
635
  if ( empty( $terms ) && $this->child->is_type( 'variation' ) ) {
636
 
637
  $parent_terms = get_the_terms( wc_gzd_get_crud_data( $this->child, 'parent' ), 'product_delivery_time' );
638
 
639
+ if ( ! empty( $parent_terms ) && ! is_wp_error( $parent_terms ) ) {
640
  $terms = $parent_terms;
641
+ }
642
  }
643
 
644
+ if ( is_wp_error( $terms ) || empty( $terms ) ) {
645
  return false;
646
+ }
647
 
648
+ return $terms[0];
649
  }
650
 
651
  /**
693
  '{delivery_time}' => $html,
694
  );
695
 
696
+ $html = apply_filters( 'woocommerce_germanized_delivery_time_html',
697
+ wc_gzd_replace_label_shortcodes( get_option( 'woocommerce_gzd_delivery_time_text' ), $replacements ),
698
+ get_option( 'woocommerce_gzd_delivery_time_text' ),
699
+ $html,
700
+ $this
701
+ );
702
  } else {
703
  $html = '';
704
  }
includes/admin/class-wc-gzd-admin-order.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Hook into item tax recalculation to ensure tax shares are calculated correctly.
4
+ *
5
+ * @author Vendidero
6
+ * @category Admin
7
+ * @package WooCommerceGermanized/Admin
8
+ * @version 2.3.0
9
+ */
10
+
11
+ if ( ! defined( 'ABSPATH' ) )
12
+ exit; // Exit if accessed directly
13
+
14
+ class WC_GZD_Admin_Order {
15
+
16
+ protected static $_instance = null;
17
+
18
+ public static function instance() {
19
+ if ( is_null( self::$_instance ) ) {
20
+ self::$_instance = new self();
21
+ }
22
+
23
+ return self::$_instance;
24
+ }
25
+
26
+ public function __construct() {
27
+ if ( 'yes' === get_option( 'woocommerce_gzd_shipping_tax' ) ) {
28
+ add_action( 'woocommerce_order_item_shipping_after_calculate_taxes', array( $this, 'adjust_item_taxes' ), 10, 2 );
29
+ }
30
+
31
+ if ( 'yes' === get_option( 'woocommerce_gzd_fee_tax' ) ) {
32
+ add_action( 'woocommerce_order_item_fee_after_calculate_taxes', array( $this, 'adjust_item_taxes' ), 10, 2 );
33
+ }
34
+ }
35
+
36
+ public function adjust_item_taxes( $item, $for ) {
37
+
38
+ if ( $item->get_total() <= 0 ) {
39
+ return;
40
+ }
41
+
42
+ if ( $order = $item->get_order() ) {
43
+
44
+ // Calculate tax shares
45
+ $tax_share = $this->get_order_tax_share( $order, is_a( $item, 'WC_Order_Item_Shipping' ) ? 'shipping' : 'fee' );
46
+
47
+ if ( $tax_share && ! empty( $tax_share ) ) {
48
+ $taxes = array();
49
+ $old_item = $order->get_item( $item->get_id() );
50
+
51
+ // Lets grab a fresh copy (loaded from DB) to make sure we are not dependent on Woo's calculated taxes in $item.
52
+ if ( $old_item ) {
53
+ $item_total = $old_item->get_total() + $old_item->get_total_tax();
54
+ } else {
55
+ $item_total = $item->get_total() + $item->get_totaL_tax();
56
+ }
57
+
58
+ foreach ( $tax_share as $rate => $class ) {
59
+ $tax_rates = WC_Tax::get_rates( $rate );
60
+ $taxes = $taxes + WC_Tax::calc_tax( ( $item_total * $class['share'] ), $tax_rates, true );
61
+ }
62
+
63
+ $item->set_taxes( array( 'total' => $taxes ) );
64
+
65
+ // The new net total equals old gross total minus new tax totals
66
+ $item->set_total( $item_total - $item->get_total_tax() );
67
+ }
68
+ }
69
+ }
70
+
71
+ public function get_order_tax_share( $order, $type = 'shipping' ) {
72
+ $tax_shares = array();
73
+ $item_totals = 0;
74
+
75
+ foreach ( $order->get_items() as $key => $item ) {
76
+
77
+ $_product = $item->get_product();
78
+ $no_shipping = false;
79
+
80
+ if ( ! $_product ) {
81
+ continue;
82
+ }
83
+
84
+ if ( 'shipping' === $type ) {
85
+ if ( $_product->is_virtual() || wc_gzd_get_gzd_product( $_product )->is_virtual_vat_exception() ) {
86
+ $no_shipping = true;
87
+ }
88
+
89
+ $tax_status = wc_gzd_get_crud_data( $_product, 'tax_status' );
90
+ $tax_class = $_product->get_tax_class();
91
+
92
+ if ( 'none' === $tax_status || 'zero-rate' === $tax_class ) {
93
+ $no_shipping = true;
94
+ }
95
+ }
96
+
97
+ if ( apply_filters( 'woocommerce_gzd_order_item_not_supporting_tax_share', $no_shipping, $item, $key, $type ) ) {
98
+ continue;
99
+ }
100
+
101
+ $class = $_product->get_tax_class();
102
+
103
+ if ( ! isset( $tax_shares[ $class ] ) ) {
104
+ $tax_shares[ $class ] = array();
105
+ $tax_shares[ $class ]['total'] = 0;
106
+ }
107
+
108
+ $item_total = ( $item->get_total() + $item->get_total_tax() );
109
+
110
+ $tax_shares[ $class ]['total'] += $item_total;
111
+
112
+ $item_totals += $item_total;
113
+ }
114
+
115
+ if ( ! empty( $tax_shares ) ) {
116
+ $default = ( $item_totals == 0 ? 1 / sizeof( $tax_shares ) : 0 );
117
+
118
+ foreach ( $tax_shares as $key => $class ) {
119
+ $tax_shares[ $key ]['share'] = ( $item_totals > 0 ? $class['total'] / $item_totals : $default );
120
+ }
121
+ }
122
+
123
+ return $tax_shares;
124
+ }
125
+ }
126
+
127
+ WC_GZD_Admin_Order::instance();
includes/admin/class-wc-gzd-admin.php CHANGED
@@ -182,11 +182,12 @@ class WC_GZD_Admin {
182
 
183
  public function set_order_parcel_delivery_opted_in( $order ) {
184
 
185
- if ( ! wc_gzd_get_crud_data( $order, 'parcel_delivery_opted_in' ) )
186
  return;
 
187
 
188
  ?>
189
- <p><strong style="display: block;"><?php _e( 'Parcel Delivery Data Transfer:', 'woocommerce-germanized' ) ?></strong>
190
  <span><?php echo ( wc_gzd_order_supports_parcel_delivery_reminder( wc_gzd_get_crud_data( $order, 'id' ) ) ? __( 'allowed', 'woocommerce-germanized' ) : __( 'not allowed', 'woocommerce-germanized' ) ); ?></span>
191
  </p>
192
  <?php
182
 
183
  public function set_order_parcel_delivery_opted_in( $order ) {
184
 
185
+ if ( ! wc_gzd_get_crud_data( $order, 'parcel_delivery_opted_in' ) ) {
186
  return;
187
+ }
188
 
189
  ?>
190
+ <p class="parcel-delivery-checkbox-status"><strong style="display: block;"><?php _e( 'Parcel Delivery Data Transfer:', 'woocommerce-germanized' ) ?></strong>
191
  <span><?php echo ( wc_gzd_order_supports_parcel_delivery_reminder( wc_gzd_get_crud_data( $order, 'id' ) ) ? __( 'allowed', 'woocommerce-germanized' ) : __( 'not allowed', 'woocommerce-germanized' ) ); ?></span>
192
  </p>
193
  <?php
includes/admin/meta-boxes/class-wc-gzd-meta-box-product-data.php CHANGED
@@ -68,6 +68,11 @@ class WC_Germanized_Meta_Box_Product_Data {
68
  return;
69
  }
70
 
 
 
 
 
 
71
  $product = wc_get_product( $product_id );
72
 
73
  if ( $product->get_id() > 0 ) {
68
  return;
69
  }
70
 
71
+ // Do not update products on checkout - seems to cause problems with WPML
72
+ if ( function_exists( 'is_checkout' ) && is_checkout() ) {
73
+ return;
74
+ }
75
+
76
  $product = wc_get_product( $product_id );
77
 
78
  if ( $product->get_id() > 0 ) {
includes/class-wc-gzd-checkout.php CHANGED
@@ -710,19 +710,20 @@ class WC_GZD_Checkout {
710
  $new = array();
711
 
712
  if ( ! empty( $this->custom_fields_admin ) ) {
713
-
714
  foreach ( $this->custom_fields_admin as $key => $custom_field ) {
715
 
716
  $new = array();
717
 
718
- if ( isset( $custom_field['address_type'] ) && $custom_field['address_type'] !== $type )
719
  continue;
 
720
 
721
  if ( ! empty( $fields ) ) {
722
-
723
  foreach ( $fields as $name => $field ) {
724
- if ( $name == $custom_field['before'] && ! isset( $custom_field['override'] ) )
 
725
  $new[ $key ] = $custom_field;
 
726
 
727
  $new[ $name ] = $field;
728
  }
710
  $new = array();
711
 
712
  if ( ! empty( $this->custom_fields_admin ) ) {
 
713
  foreach ( $this->custom_fields_admin as $key => $custom_field ) {
714
 
715
  $new = array();
716
 
717
+ if ( isset( $custom_field['address_type'] ) && $custom_field['address_type'] !== $type ) {
718
  continue;
719
+ }
720
 
721
  if ( ! empty( $fields ) ) {
 
722
  foreach ( $fields as $name => $field ) {
723
+
724
+ if ( $name == $custom_field['before'] && ! isset( $custom_field['override'] ) ) {
725
  $new[ $key ] = $custom_field;
726
+ }
727
 
728
  $new[ $name ] = $field;
729
  }
includes/class-wc-gzd-customer-helper.php CHANGED
@@ -210,7 +210,7 @@ class WC_GZD_Customer_Helper {
210
  }
211
  }
212
 
213
- public function registration_redirect( $redirect ) {
214
  return apply_filters( 'woocommerce_gzd_customer_registration_redirect', add_query_arg( array( 'account' => 'activate' ), wc_gzd_get_page_permalink( 'myaccount' ) ) );
215
  }
216
 
@@ -222,12 +222,11 @@ class WC_GZD_Customer_Helper {
222
 
223
  // Has not been activated yet
224
  if ( $this->enable_double_opt_in_for_user( $user_id ) && ! wc_gzd_is_customer_activated( $user_id ) ) {
225
- add_filter( 'woocommerce_registration_redirect', array( $this, 'registration_redirect' ) );
226
- return false;
227
  }
228
 
229
  return true;
230
-
231
  }
232
 
233
  public function get_double_opt_in_user_roles() {
@@ -429,18 +428,21 @@ class WC_GZD_Customer_Helper {
429
  */
430
  public function customer_new_account_activation( $customer_id, $new_customer_data = array(), $password_generated = false ) {
431
 
432
- if ( ! $customer_id )
433
  return;
 
434
 
435
- if ( ! $this->enable_double_opt_in_for_user( $customer_id ) )
436
  return;
 
437
 
438
  $user_pass = ! empty( $new_customer_data['user_pass'] ) ? $new_customer_data['user_pass'] : '';
439
  $user_activation = $this->get_customer_activation_meta( $customer_id );
440
  $user_activation_url = $this->get_customer_activation_url( $user_activation );
441
 
442
- if ( $email = WC_germanized()->emails->get_email_instance_by_id( 'customer_new_account_activation' ) )
443
  $email->trigger( $customer_id, $user_activation, $user_activation_url, $user_pass, $password_generated );
 
444
  }
445
 
446
  public function get_customer_activation_url( $key ) {
210
  }
211
  }
212
 
213
+ protected function registration_redirect() {
214
  return apply_filters( 'woocommerce_gzd_customer_registration_redirect', add_query_arg( array( 'account' => 'activate' ), wc_gzd_get_page_permalink( 'myaccount' ) ) );
215
  }
216
 
222
 
223
  // Has not been activated yet
224
  if ( $this->enable_double_opt_in_for_user( $user_id ) && ! wc_gzd_is_customer_activated( $user_id ) ) {
225
+ wp_redirect( wp_validate_redirect( $this->registration_redirect() ) ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
226
+ exit;
227
  }
228
 
229
  return true;
 
230
  }
231
 
232
  public function get_double_opt_in_user_roles() {
428
  */
429
  public function customer_new_account_activation( $customer_id, $new_customer_data = array(), $password_generated = false ) {
430
 
431
+ if ( ! $customer_id ) {
432
  return;
433
+ }
434
 
435
+ if ( ! $this->enable_double_opt_in_for_user( $customer_id ) ) {
436
  return;
437
+ }
438
 
439
  $user_pass = ! empty( $new_customer_data['user_pass'] ) ? $new_customer_data['user_pass'] : '';
440
  $user_activation = $this->get_customer_activation_meta( $customer_id );
441
  $user_activation_url = $this->get_customer_activation_url( $user_activation );
442
 
443
+ if ( $email = WC_germanized()->emails->get_email_instance_by_id( 'customer_new_account_activation' ) ) {
444
  $email->trigger( $customer_id, $user_activation, $user_activation_url, $user_pass, $password_generated );
445
+ }
446
  }
447
 
448
  public function get_customer_activation_url( $key ) {
includes/class-wc-gzd-dhl-parcel-shops.php CHANGED
@@ -29,6 +29,9 @@ class WC_GZD_DHL_Parcel_Shops {
29
  add_filter( 'woocommerce_gzd_custom_checkout_fields', array( $this, 'init_fields' ), 10, 1 );
30
  add_filter( 'woocommerce_gzd_custom_checkout_admin_fields', array( $this, 'init_admin_fields' ), 10, 1 );
31
 
 
 
 
32
  add_action( 'woocommerce_gzd_registered_scripts', array( $this, 'load_scripts' ), 10, 3 );
33
  add_action( 'woocommerce_gzd_localized_scripts', array( $this, 'localize_scripts' ), 10, 1 );
34
 
@@ -41,7 +44,6 @@ class WC_GZD_DHL_Parcel_Shops {
41
 
42
  // Customer fields
43
  add_filter( 'woocommerce_customer_meta_fields', array( $this, 'init_profile_fields' ), 10, 1 );
44
-
45
  add_action( 'woocommerce_before_checkout_form', array( $this, 'maybe_hide_fields_before_rendering' ), 10, 1 );
46
 
47
  if ( $this->is_finder_enabled() ) {
@@ -52,9 +54,27 @@ class WC_GZD_DHL_Parcel_Shops {
52
  }
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  public function maybe_hide_fields_before_rendering( $checkout ) {
56
 
57
- $hide_fields = false;
58
  $chosen_shipping_methods = wc_gzd_get_chosen_shipping_rates();
59
 
60
  foreach ( $chosen_shipping_methods as $rate ) {
@@ -69,8 +89,9 @@ class WC_GZD_DHL_Parcel_Shops {
69
  }
70
 
71
  public function get_disabled_shipping_methods() {
72
- if ( get_option( 'woocommerce_gzd_display_checkout_shipping_rate_select' ) !== 'yes' )
73
  return array();
 
74
 
75
  return get_option( 'woocommerce_gzd_dhl_parcel_shop_disabled_shipping_methods', array() );
76
  }
@@ -95,28 +116,30 @@ class WC_GZD_DHL_Parcel_Shops {
95
  public function set_address_format( $formats ) {
96
  foreach( $this->get_supported_countries() as $country ) {
97
 
98
- if ( ! array_key_exists( $country, $formats ) )
99
- continue;
 
100
 
101
  $format = $formats[ $country ];
102
  $format = str_replace( "{name}", "{name}\n{parcelshop_post_number}", $format );
 
103
  $formats[ $country ] = $format;
104
  }
105
 
106
  return $formats;
107
  }
108
 
109
- public function set_formatted_shipping_address( $fields = array(), $order ) {
110
  $fields['parcelshop_post_number'] = '';
111
 
112
- if ( wc_gzd_get_crud_data( $order, 'shipping_parcelshop' ) ) {
113
  $fields['parcelshop_post_number'] = wc_gzd_get_crud_data( $order, 'shipping_parcelshop_post_number' );
114
  }
115
 
116
  return $fields;
117
  }
118
 
119
- public function set_formatted_billing_address( $fields = array(), $order ) {
120
  $fields['parcelshop_post_number'] = '';
121
 
122
  return $fields;
@@ -241,12 +264,6 @@ class WC_GZD_DHL_Parcel_Shops {
241
  return $fields;
242
  }
243
 
244
- public function order_has_parcel_shop_delivery( $order_id ) {
245
- $number = get_post_meta( $order_id, '_shipping_parcelshop_post_number', true );
246
-
247
- return ( get_post_meta( $order_id, '_shipping_parcelshop', true ) && ! empty( $number ) ) ? true : false;
248
- }
249
-
250
  public function validate_address_fields( $value ) {
251
 
252
  if ( $value && ! empty( $value ) ) {
29
  add_filter( 'woocommerce_gzd_custom_checkout_fields', array( $this, 'init_fields' ), 10, 1 );
30
  add_filter( 'woocommerce_gzd_custom_checkout_admin_fields', array( $this, 'init_admin_fields' ), 10, 1 );
31
 
32
+ // Maybe remove post number if the checkbox has not been checked
33
+ add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'save_fields' ), 20 );
34
+
35
  add_action( 'woocommerce_gzd_registered_scripts', array( $this, 'load_scripts' ), 10, 3 );
36
  add_action( 'woocommerce_gzd_localized_scripts', array( $this, 'localize_scripts' ), 10, 1 );
37
 
44
 
45
  // Customer fields
46
  add_filter( 'woocommerce_customer_meta_fields', array( $this, 'init_profile_fields' ), 10, 1 );
 
47
  add_action( 'woocommerce_before_checkout_form', array( $this, 'maybe_hide_fields_before_rendering' ), 10, 1 );
48
 
49
  if ( $this->is_finder_enabled() ) {
54
  }
55
  }
56
 
57
+ public function save_fields( $order_id ) {
58
+ $checkout = WC()->checkout();
59
+ $send_to_parcel_box = $checkout->get_posted_address_data( 'parcelshop', 'shipping' );
60
+ $order = wc_get_order( $order_id );
61
+
62
+ if ( ! $order ) {
63
+ return;
64
+ }
65
+
66
+ if ( ! $send_to_parcel_box || empty( $send_to_parcel_box ) ) {
67
+ wc_gzd_unset_crud_meta_data( $order, 'shipping_parcelshop_post_number' );
68
+
69
+ if ( wc_gzd_get_dependencies()->woocommerce_version_supports_crud() ) {
70
+ $order->save();
71
+ }
72
+ }
73
+ }
74
+
75
  public function maybe_hide_fields_before_rendering( $checkout ) {
76
 
77
+ $hide_fields = false;
78
  $chosen_shipping_methods = wc_gzd_get_chosen_shipping_rates();
79
 
80
  foreach ( $chosen_shipping_methods as $rate ) {
89
  }
90
 
91
  public function get_disabled_shipping_methods() {
92
+ if ( get_option( 'woocommerce_gzd_display_checkout_shipping_rate_select' ) !== 'yes' ) {
93
  return array();
94
+ }
95
 
96
  return get_option( 'woocommerce_gzd_dhl_parcel_shop_disabled_shipping_methods', array() );
97
  }
116
  public function set_address_format( $formats ) {
117
  foreach( $this->get_supported_countries() as $country ) {
118
 
119
+ if ( ! array_key_exists( $country, $formats ) ) {
120
+ continue;
121
+ }
122
 
123
  $format = $formats[ $country ];
124
  $format = str_replace( "{name}", "{name}\n{parcelshop_post_number}", $format );
125
+
126
  $formats[ $country ] = $format;
127
  }
128
 
129
  return $formats;
130
  }
131
 
132
+ public function set_formatted_shipping_address( $fields, $order ) {
133
  $fields['parcelshop_post_number'] = '';
134
 
135
+ if ( wc_gzd_get_crud_data( $order, 'shipping_parcelshop_post_number' ) ) {
136
  $fields['parcelshop_post_number'] = wc_gzd_get_crud_data( $order, 'shipping_parcelshop_post_number' );
137
  }
138
 
139
  return $fields;
140
  }
141
 
142
+ public function set_formatted_billing_address( $fields, $order ) {
143
  $fields['parcelshop_post_number'] = '';
144
 
145
  return $fields;
264
  return $fields;
265
  }
266
 
 
 
 
 
 
 
267
  public function validate_address_fields( $value ) {
268
 
269
  if ( $value && ! empty( $value ) ) {
includes/class-wc-gzd-emails.php CHANGED
@@ -241,13 +241,13 @@ class WC_GZD_Emails {
241
  }
242
 
243
  private function set_footer_attachments() {
244
-
245
  // Order attachments
246
- $attachment_order = wc_gzd_get_email_attachment_order();
247
  $this->footer_attachments = array();
248
 
249
- foreach ( $attachment_order as $key => $order )
250
  $this->footer_attachments[ 'woocommerce_gzd_mail_attach_' . $key ] = $key;
 
251
  }
252
 
253
  public function admin_hooks() {
@@ -276,9 +276,9 @@ class WC_GZD_Emails {
276
  $mails = $this->mailer->get_emails();
277
 
278
  if ( ! empty( $mails ) ) {
279
-
280
- foreach ( $mails as $mail )
281
  add_action( 'woocommerce_germanized_email_footer_' . $mail->id, array( $this, 'hook_mail_footer' ), 10, 1 );
 
282
  }
283
 
284
  // Set email filters
@@ -601,12 +601,16 @@ class WC_GZD_Emails {
601
  */
602
  public function hook_mail_footer( $mail ) {
603
  if ( ! empty( $this->footer_attachments ) ) {
604
- foreach ( $this->footer_attachments as $option_key => $page_option ) {
605
- $option = wc_get_page_id ( $page_option );
606
- if ( $option == -1 || ! get_option( $option_key ) )
 
 
607
  continue;
608
- if ( in_array( $mail->id, get_option( $option_key ) ) && apply_filters( 'woocommerce_gzd_attach_email_footer', true, $mail, $page_option ) ) {
609
- $this->attach_page_content( $option, $mail->get_email_type() );
 
 
610
  }
611
  }
612
  }
@@ -617,6 +621,7 @@ class WC_GZD_Emails {
617
  */
618
  public function add_template_footers() {
619
  $type = $this->get_current_email_object();
 
620
  if ( $type ) {
621
  do_action( 'woocommerce_germanized_email_footer_' . $type->id, $type );
622
  }
@@ -678,16 +683,20 @@ class WC_GZD_Emails {
678
  *
679
  * @param integer $page_id
680
  */
681
- public function attach_page_content( $page_id, $email_type = 'html' ) {
682
 
683
  do_action( 'woocommerce_germanized_attach_email_footer', $page_id, $email_type );
 
 
684
 
685
  remove_shortcode( 'revocation_form' );
686
  add_shortcode( 'revocation_form', array( $this, 'revocation_form_replacement' ) );
687
 
688
  $template = 'emails/email-footer-attachment.php';
689
- if ( $email_type == 'plain' )
 
690
  $template = 'emails/plain/email-footer-attachment.php';
 
691
 
692
  wc_get_template( $template, array(
693
  'post_attach' => get_post( $page_id ),
241
  }
242
 
243
  private function set_footer_attachments() {
 
244
  // Order attachments
245
+ $attachment_order = wc_gzd_get_email_attachment_order();
246
  $this->footer_attachments = array();
247
 
248
+ foreach ( $attachment_order as $key => $order ) {
249
  $this->footer_attachments[ 'woocommerce_gzd_mail_attach_' . $key ] = $key;
250
+ }
251
  }
252
 
253
  public function admin_hooks() {
276
  $mails = $this->mailer->get_emails();
277
 
278
  if ( ! empty( $mails ) ) {
279
+ foreach ( $mails as $mail ) {
 
280
  add_action( 'woocommerce_germanized_email_footer_' . $mail->id, array( $this, 'hook_mail_footer' ), 10, 1 );
281
+ }
282
  }
283
 
284
  // Set email filters
601
  */
602
  public function hook_mail_footer( $mail ) {
603
  if ( ! empty( $this->footer_attachments ) ) {
604
+
605
+ foreach ( $this->footer_attachments as $option_key => $page_option ) {
606
+ $option = wc_get_page_id ( $page_option );
607
+
608
+ if ( $option == -1 || ! get_option( $option_key ) ) {
609
  continue;
610
+ }
611
+
612
+ if ( in_array( $mail->id, get_option( $option_key ) ) && apply_filters( 'woocommerce_gzd_attach_email_footer', true, $mail, $page_option ) ) {
613
+ $this->attach_page_content( $option, $mail, $mail->get_email_type() );
614
  }
615
  }
616
  }
621
  */
622
  public function add_template_footers() {
623
  $type = $this->get_current_email_object();
624
+
625
  if ( $type ) {
626
  do_action( 'woocommerce_germanized_email_footer_' . $type->id, $type );
627
  }
683
  *
684
  * @param integer $page_id
685
  */
686
+ public function attach_page_content( $page_id, $mail, $email_type = 'html' ) {
687
 
688
  do_action( 'woocommerce_germanized_attach_email_footer', $page_id, $email_type );
689
+
690
+ $page_id = apply_filters( 'woocommerce_germanized_attach_email_footer_page_id', $page_id, $mail );
691
 
692
  remove_shortcode( 'revocation_form' );
693
  add_shortcode( 'revocation_form', array( $this, 'revocation_form_replacement' ) );
694
 
695
  $template = 'emails/email-footer-attachment.php';
696
+
697
+ if ( $email_type == 'plain' ) {
698
  $template = 'emails/plain/email-footer-attachment.php';
699
+ }
700
 
701
  wc_get_template( $template, array(
702
  'post_attach' => get_post( $page_id ),
includes/class-wc-gzd-hook-priorities.php CHANGED
@@ -77,6 +77,10 @@ class WC_GZD_Hook_Priorities {
77
  'single_price_unit' => $this->get_priority( 'woocommerce_single_product_summary', 'woocommerce_template_single_price' ) + 1,
78
  'single_legal_info' => $this->get_priority( 'woocommerce_single_product_summary', 'woocommerce_template_single_price' ) + 2,
79
  'single_delivery_time_info' => 27,
 
 
 
 
80
  'single_small_business_info' => 30,
81
  'single_product_units' => 5,
82
  'loop_price_unit' => 10,
77
  'single_price_unit' => $this->get_priority( 'woocommerce_single_product_summary', 'woocommerce_template_single_price' ) + 1,
78
  'single_legal_info' => $this->get_priority( 'woocommerce_single_product_summary', 'woocommerce_template_single_price' ) + 2,
79
  'single_delivery_time_info' => 27,
80
+ 'grouped_single_price_unit' => 10,
81
+ 'grouped_single_legal_info' => 20,
82
+ 'grouped_single_delivery_time_info' => 30,
83
+ 'grouped_single_product_units' => 40,
84
  'single_small_business_info' => 30,
85
  'single_product_units' => 5,
86
  'loop_price_unit' => 10,
includes/class-wc-gzd-product-factory.php CHANGED
@@ -21,8 +21,11 @@ class WC_GZD_Product_Factory extends WC_Product_Factory {
21
  */
22
  public function get_product( $the_product = false, $args = array() ) {
23
  $product = $this->get_product_standalone( $the_product, $args );
24
- if ( is_object( $product ) )
 
25
  $product->gzd_product = $this->get_gzd_product( $product );
 
 
26
  return $product;
27
  }
28
 
@@ -49,8 +52,9 @@ class WC_GZD_Product_Factory extends WC_Product_Factory {
49
 
50
  $classname = apply_filters( 'woocommerce_gzd_product_classname', $classname, $type );
51
 
52
- if ( class_exists( $classname ) )
53
  return new $classname( $product );
 
54
 
55
  return new WC_GZD_Product( $product );
56
  }
21
  */
22
  public function get_product( $the_product = false, $args = array() ) {
23
  $product = $this->get_product_standalone( $the_product, $args );
24
+
25
+ if ( is_object( $product ) ) {
26
  $product->gzd_product = $this->get_gzd_product( $product );
27
+ }
28
+
29
  return $product;
30
  }
31
 
52
 
53
  $classname = apply_filters( 'woocommerce_gzd_product_classname', $classname, $type );
54
 
55
+ if ( class_exists( $classname ) ) {
56
  return new $classname( $product );
57
+ }
58
 
59
  return new WC_GZD_Product( $product );
60
  }
includes/class-wc-gzd-product-grouped.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit; // Exit if accessed directly
5
+
6
+ /**
7
+ * WooCommerce Germanized Grouped Product
8
+ *
9
+ * The WC_GZD_Product_Grouped Class is used to offer additional functionality for every grouped product.
10
+ *
11
+ * @class WC_GZD_Product
12
+ * @version 1.0.0
13
+ * @author Vendidero
14
+ */
15
+ class WC_GZD_Product_Grouped extends WC_GZD_Product {
16
+
17
+ protected $child_prices = null;
18
+
19
+ protected $has_unit_price = false;
20
+
21
+ /**
22
+ * Callback for array filter to get visible grouped products only.
23
+ *
24
+ * @since 3.1.0
25
+ * @param WC_Product $product WC_Product object.
26
+ * @return bool
27
+ */
28
+ public function _filter_visible_grouped( $product ) {
29
+ return $product && is_a( $product, 'WC_GZD_Product' ) && ( 'publish' === $product->get_status() || current_user_can( 'edit_product', $product->get_id() ) );
30
+ }
31
+
32
+ protected function get_child_unit_data() {
33
+ if ( is_null( $this->child_prices ) ) {
34
+ $children = array_filter( array_map( 'wc_gzd_get_gzd_product', $this->get_children() ), array( $this, '_filter_visible_grouped' ) );
35
+ $this->child_prices = array();
36
+
37
+ if ( ! empty( $children ) ) {
38
+ $this->has_unit_price = true;
39
+
40
+ foreach ( $children as $child ) {
41
+ if ( $child->has_unit() ) {
42
+ $unit = $child->get_unit_raw();
43
+
44
+ if ( ! isset( $this->child_prices[ $unit ] ) ) {
45
+ $this->child_prices[ $unit ] = array();
46
+ $this->child_prices[ $unit ]['prices'] = array(
47
+ 'incl' => array(
48
+ 'price' => array(),
49
+ 'regular_price' => array(),
50
+ 'sale_price' => array(),
51
+ ),
52
+ 'excl' => array(
53
+ 'price' => array(),
54
+ 'regular_price' => array(),
55
+ 'sale_price' => array(),
56
+ ),
57
+ );
58
+ }
59
+
60
+ if ( ! isset( $this->child_prices[ $unit ]['base'] ) ) {
61
+ $this->child_prices[ $unit ]['base'] = $child->get_unit_base_raw();
62
+ }
63
+
64
+ // Recalculate new prices
65
+ $prices_incl = wc_gzd_recalculate_unit_price( array(
66
+ 'base' => $this->child_prices[ $unit ]['base'],
67
+ 'products' => $child->get_unit_products(),
68
+ ), $child );
69
+
70
+ $prices_excl = wc_gzd_recalculate_unit_price( array(
71
+ 'base' => $this->child_prices[ $unit ]['base'],
72
+ 'products' => $child->get_unit_products(),
73
+ 'tax_mode' => 'excl',
74
+ ), $child );
75
+
76
+ if ( empty( $prices_incl ) || empty( $prices_excl ) ) {
77
+ $this->has_unit_price = false;
78
+ continue;
79
+ }
80
+
81
+ $this->child_prices[ $unit ]['prices']['incl']['price'][] = $prices_incl['unit'];
82
+ $this->child_prices[ $unit ]['prices']['incl']['regular_price'][] = $prices_incl['regular'];
83
+ $this->child_prices[ $unit ]['prices']['incl']['sale_price'][] = $prices_incl['sale'];
84
+
85
+ $this->child_prices[ $unit ]['prices']['excl']['price'][] = $prices_excl['unit'];
86
+ $this->child_prices[ $unit ]['prices']['excl']['regular_price'][] = $prices_excl['regular'];
87
+ $this->child_prices[ $unit ]['prices']['excl']['sale_price'][] = $prices_excl['sale'];
88
+ } else {
89
+ $this->has_unit_price = false;
90
+ }
91
+ }
92
+ }
93
+
94
+ if ( ! empty( $this->child_prices ) ) {
95
+ foreach( $this->child_prices as $unit => $data ) {
96
+ asort( $this->child_prices[ $unit ]['prices']['incl']['price'] );
97
+ asort( $this->child_prices[ $unit ]['prices']['incl']['regular_price'] );
98
+ asort( $this->child_prices[ $unit ]['prices']['incl']['sale_price'] );
99
+ asort( $this->child_prices[ $unit ]['prices']['excl']['price'] );
100
+ asort( $this->child_prices[ $unit ]['prices']['excl']['regular_price'] );
101
+ asort( $this->child_prices[ $unit ]['prices']['excl']['sale_price'] );
102
+ }
103
+ }
104
+ }
105
+
106
+ return $this->child_prices;
107
+ }
108
+
109
+ protected function get_child_unit_prices() {
110
+ $tax_display = get_option( 'woocommerce_tax_display_shop', 'excl' );
111
+ $data = $this->get_child_unit_data();
112
+ $prices = array();
113
+
114
+ if ( ! empty( $data ) ) {
115
+ $prices = array_values( $data );
116
+ $prices = $prices[0]['prices'][ $tax_display ];
117
+ }
118
+
119
+ return $prices;
120
+ }
121
+
122
+ protected function get_child_units() {
123
+ $data = $this->get_child_unit_data();
124
+
125
+ return array_keys( $data );
126
+ }
127
+
128
+ public function get_unit() {
129
+ $data = $this->get_child_unit_data();
130
+
131
+ if ( ! empty( $data ) ) {
132
+ $keys = array_keys( $data );
133
+ $unit = $keys[0];
134
+
135
+ if ( $unit ) {
136
+ return WC_germanized()->units->$unit;
137
+ }
138
+ }
139
+
140
+ return '';
141
+ }
142
+
143
+ /**
144
+ * Returns unit base html
145
+ *
146
+ * @return string
147
+ */
148
+ public function get_unit_base_raw() {
149
+ $data = $this->get_child_unit_data();
150
+ $base_data = array();
151
+ $base = false;
152
+
153
+ if ( ! empty( $data ) ) {
154
+ $base_data = array_values( $data );
155
+ $base = $base_data[0]['base'];
156
+ }
157
+
158
+ return $base;
159
+ }
160
+
161
+ public function get_delivery_time_html() {
162
+ if ( apply_filters( 'woocommerce_gzd_hide_delivery_time_for_grouped_product', true, $this ) ) {
163
+ return '';
164
+ }
165
+
166
+ return parent::get_delivery_time_html();
167
+ }
168
+
169
+ /**
170
+ * Returns unit base html
171
+ *
172
+ * @return string
173
+ */
174
+ public function get_unit_base() {
175
+ $base = $this->get_unit_base_raw();
176
+
177
+ return ( $base ) ? ( $base != apply_filters( 'woocommerce_gzd_unit_base_hide_amount', 1 ) ? '<span class="unit-base">' . $base . '</span>' . apply_filters( 'wc_gzd_unit_price_base_seperator', ' ' ) : '' ) . '<span class="unit">' . $this->get_unit() . '</span>' : '';
178
+ }
179
+
180
+ /**
181
+ * Show unit prices only if every product has a unit price and shares the same unit.
182
+ *
183
+ * @return bool
184
+ */
185
+ public function has_unit() {
186
+ $data = $this->get_child_unit_data();
187
+
188
+ return $this->has_unit_price && 1 === sizeof( $data );
189
+ }
190
+
191
+ /**
192
+ * Returns the price in html format.
193
+ *
194
+ * @param string $price (default: '').
195
+ * @return string
196
+ */
197
+ public function get_unit_html( $show_sale = true ) {
198
+ if ( $this->has_unit() ) {
199
+
200
+ $prices = $this->get_child_unit_prices();
201
+ $text = get_option( 'woocommerce_gzd_unit_price_text' );
202
+
203
+ $min_price = current( $prices['price'] );
204
+ $max_price = end( $prices['price'] );
205
+ $min_reg_price = current( $prices['regular_price'] );
206
+ $max_reg_price = end( $prices['regular_price'] );
207
+
208
+ if ( wc_gzd_get_dependencies()->woocommerce_version_supports_crud() ) {
209
+
210
+ if ( $min_price !== $max_price ) {
211
+ $price = wc_format_price_range( $min_price, $max_price );
212
+ } elseif ( $this->is_on_sale() && $min_reg_price === $max_reg_price ) {
213
+ $price = wc_format_sale_price( wc_price( $max_reg_price ), wc_price( $min_price ) );
214
+ } else {
215
+ $price = wc_price( $min_price );
216
+ }
217
+
218
+ $price = apply_filters( 'woocommerce_gzd_grouped_unit_price_html', $price, $this );
219
+
220
+ } else {
221
+
222
+ $price = $min_price !== $max_price ? sprintf( _x( '%1$s&ndash;%2$s', 'Price range: from-to', 'woocommerce-germanized' ), wc_price( $min_price ), wc_price( $max_price ) ) : wc_price( $min_price );
223
+
224
+ if ( $this->is_on_sale() ) {
225
+ $min_regular_price = current( $prices['regular_price'] );
226
+ $max_regular_price = end( $prices['regular_price'] );
227
+ $regular_price = $min_regular_price !== $max_regular_price ? sprintf( _x( '%1$s&ndash;%2$s', 'Price range: from-to', 'woocommerce-germanized' ), wc_price( $min_regular_price ), wc_price( $max_regular_price ) ) : wc_price( $min_regular_price );
228
+ $price = apply_filters( 'woocommerce_gzd_grouped_unit_sale_price_html', $this->get_price_html_from_to( $regular_price, $price, false ), $this );
229
+ } else {
230
+ $price = apply_filters( 'woocommerce_gzd_grouped_unit_price_html', $price, $this );
231
+ }
232
+ }
233
+
234
+ if ( strpos( $text, '{price}' ) !== false ) {
235
+ $replacements = array(
236
+ '{price}' => $price . apply_filters( 'wc_gzd_unit_price_seperator', ' / ' ) . $this->get_unit_base(),
237
+ );
238
+ } else {
239
+ $replacements = array(
240
+ '{base_price}' => $price,
241
+ '{unit}' => '<span class="unit">' . $this->get_unit() . '</span>',
242
+ '{base}' => $this->get_unit_base(),
243
+ );
244
+ }
245
+
246
+ $price = wc_gzd_replace_label_shortcodes( $text, $replacements );
247
+ }
248
+
249
+ return apply_filters( 'woocommerce_gzd_unit_price_html', $price, $this );
250
+ }
251
+ }
includes/gateways/direct-debit/class-wc-gzd-gateway-direct-debit.php CHANGED
@@ -552,26 +552,27 @@ Please notice: Period for pre-information of the SEPA direct debit is shortened
552
 
553
  public function generate_mandate() {
554
 
555
- if ( ! $this->is_available() )
556
  exit();
 
557
 
558
- if ( ! isset( $_GET[ '_wpnonce' ] ) || ! wp_verify_nonce( $_GET[ '_wpnonce' ], 'show_direct_debit' ) )
559
  exit();
 
560
 
561
  $params = array(
562
- 'account_holder' => wc_clean( isset( $_GET[ 'debit_holder' ] ) ? $_GET[ 'debit_holder' ] : '' ),
563
- 'account_iban' => strtoupper( wc_clean( isset( $_GET[ 'debit_iban' ] ) ? $_GET[ 'debit_iban' ] : '' ) ),
564
- 'account_swift' => strtoupper( wc_clean( isset( $_GET[ 'debit_swift' ] ) ? $_GET[ 'debit_swift' ] : '' ) ),
565
- 'street' => wc_clean( isset( $_GET[ 'address' ] ) ? $_GET[ 'address' ] : '' ),
566
- 'postcode' => wc_clean( isset( $_GET[ 'postcode' ] ) ? $_GET[ 'postcode' ] : '' ),
567
- 'city' => wc_clean( isset( $_GET[ 'city' ] ) ? $_GET[ 'city' ] : '' ),
568
- 'country' => ( isset( $_GET[ 'country' ] ) && isset( WC()->countries->countries[ $_GET[ 'country' ] ] ) ? WC()->countries->countries[ $_GET[ 'country' ] ] : '' ),
569
  'mandate_type_text' => apply_filters( 'woocommerce_gzd_direct_debit_mandate_type_text', __( 'a single payment', 'woocommerce-germanized' ) ),
570
  );
571
 
572
  echo $this->generate_mandate_text( $params );
573
  exit();
574
-
575
  }
576
 
577
  public function generate_mandate_by_order( $order ) {
552
 
553
  public function generate_mandate() {
554
 
555
+ if ( ! $this->is_available() ) {
556
  exit();
557
+ }
558
 
559
+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'show_direct_debit' ) ) {
560
  exit();
561
+ }
562
 
563
  $params = array(
564
+ 'account_holder' => wc_clean( isset( $_GET['debit_holder'] ) ? $_GET['debit_holder'] : '' ),
565
+ 'account_iban' => strtoupper( wc_clean( isset( $_GET['debit_iban'] ) ? $_GET['debit_iban'] : '' ) ),
566
+ 'account_swift' => strtoupper( wc_clean( isset( $_GET['debit_swift'] ) ? $_GET['debit_swift'] : '' ) ),
567
+ 'street' => wc_clean( isset( $_GET['address'] ) ? $_GET['address'] : '' ),
568
+ 'postcode' => wc_clean( isset( $_GET['postcode'] ) ? $_GET['postcode'] : '' ),
569
+ 'city' => wc_clean( isset( $_GET['city'] ) ? $_GET['city'] : '' ),
570
+ 'country' => ( isset( $_GET[ 'country' ] ) && isset( WC()->countries->countries[ $_GET['country'] ] ) ? WC()->countries->countries[ $_GET['country'] ] : '' ),
571
  'mandate_type_text' => apply_filters( 'woocommerce_gzd_direct_debit_mandate_type_text', __( 'a single payment', 'woocommerce-germanized' ) ),
572
  );
573
 
574
  echo $this->generate_mandate_text( $params );
575
  exit();
 
576
  }
577
 
578
  public function generate_mandate_by_order( $order ) {
includes/wc-gzd-core-functions.php CHANGED
@@ -73,10 +73,22 @@ function wc_gzd_get_legal_product_notice_types_by_location( $location = 'loop' )
73
  $callback = "woocommerce_gzd_template_single_{$type}";
74
 
75
  $location_types[ $type ] = array(
76
- 'priority' => wc_gzd_get_hook_priority( $location . '_' . $type ),
77
- 'callback' => $callback,
78
- 'filter' => $locations[ $location ],
 
 
79
  );
 
 
 
 
 
 
 
 
 
 
80
  }
81
  }
82
 
@@ -124,9 +136,11 @@ function wc_gzd_get_legal_cart_notice_types_by_location( $location = 'cart' ) {
124
  $callback = "wc_gzd_cart_product_{$type}";
125
 
126
  $location_types[ $type ] = array(
127
- 'priority' => wc_gzd_get_hook_priority( $location . '_product_' . $type ),
128
- 'callback' => $callback,
129
- 'filter' => $locations[ $location ],
 
 
130
  );
131
  }
132
  }
73
  $callback = "woocommerce_gzd_template_single_{$type}";
74
 
75
  $location_types[ $type ] = array(
76
+ 'priority' => wc_gzd_get_hook_priority( $location . '_' . $type ),
77
+ 'callback' => $callback,
78
+ 'filter' => $locations[ $location ],
79
+ 'is_action' => true,
80
+ 'params' => 1,
81
  );
82
+
83
+ if ( 'single' === $location ) {
84
+ $location_types[ 'grouped_' . $type ] = array(
85
+ 'priority' => wc_gzd_get_hook_priority( 'grouped_' . $location . '_' . $type ),
86
+ 'callback' => "woocommerce_gzd_template_grouped_single_{$type}",
87
+ 'filter' => 'woocommerce_grouped_product_list_column_price',
88
+ 'is_action' => false,
89
+ 'params' => 2,
90
+ );
91
+ }
92
  }
93
  }
94
 
136
  $callback = "wc_gzd_cart_product_{$type}";
137
 
138
  $location_types[ $type ] = array(
139
+ 'priority' => wc_gzd_get_hook_priority( $location . '_product_' . $type ),
140
+ 'callback' => $callback,
141
+ 'filter' => $locations[ $location ],
142
+ 'is_action' => false,
143
+ 'params' => 1,
144
  );
145
  }
146
  }
includes/wc-gzd-product-functions.php CHANGED
@@ -16,10 +16,17 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
16
  function wc_gzd_register_scheduled_unit_sales() {
17
  add_action( 'updated_post_meta', 'wc_gzd_check_price_update', 0, 4 );
18
  }
 
19
  add_action( 'woocommerce_scheduled_sales', 'wc_gzd_register_scheduled_unit_sales', 0 );
20
 
21
  function wc_gzd_get_gzd_product( $product ) {
22
-
 
 
 
 
 
 
23
  if ( ! isset( $product->gzd_product ) || ! is_object( $product->gzd_product ) ) {
24
  $factory = WC()->product_factory;
25
 
@@ -161,4 +168,58 @@ function wc_gzd_product_matches_extended_type( $types, $product ) {
161
  }
162
 
163
  return $matches_type;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
16
  function wc_gzd_register_scheduled_unit_sales() {
17
  add_action( 'updated_post_meta', 'wc_gzd_check_price_update', 0, 4 );
18
  }
19
+
20
  add_action( 'woocommerce_scheduled_sales', 'wc_gzd_register_scheduled_unit_sales', 0 );
21
 
22
  function wc_gzd_get_gzd_product( $product ) {
23
+
24
+ if ( is_numeric( $product ) ) {
25
+ $product = wc_get_product( $product );
26
+ } elseif( is_a( $product, 'WC_GZD_Product' ) ) {
27
+ return $product;
28
+ }
29
+
30
  if ( ! isset( $product->gzd_product ) || ! is_object( $product->gzd_product ) ) {
31
  $factory = WC()->product_factory;
32
 
168
  }
169
 
170
  return $matches_type;
171
+ }
172
+
173
+ function wc_gzd_recalculate_unit_price( $args = array(), $product = false ) {
174
+
175
+ $default_args = array(
176
+ 'regular_price' => 0,
177
+ 'sale_price' => 0,
178
+ 'price' => 0,
179
+ 'base' => 1,
180
+ 'products' => 1,
181
+ 'tax_mode' => 'incl',
182
+ );
183
+
184
+ if ( $product ) {
185
+ $default_args = array(
186
+ 'regular_price' => ( isset( $args['tax_mode'] ) && 'excl' === $args['tax_mode'] ) ? wc_get_price_excluding_tax( $product, array( 'price' => $product->get_regular_price() ) ) : wc_get_price_including_tax( $product, array( 'price' => $product->get_regular_price() ) ),
187
+ 'sale_price' => ( isset( $args['tax_mode'] ) && 'excl' === $args['tax_mode'] ) ? wc_get_price_excluding_tax( $product, array( 'price' => $product->get_sale_price() ) ) : wc_get_price_including_tax( $product, array( 'price' => $product->get_sale_price() ) ),
188
+ 'price' => ( isset( $args['tax_mode'] ) && 'excl' === $args['tax_mode'] ) ? wc_get_price_excluding_tax( $product ) : wc_get_price_including_tax( $product ),
189
+ 'base' => $product->get_unit_base_raw(),
190
+ 'products' => $product->get_unit_products(),
191
+ );
192
+ }
193
+
194
+ $args = wp_parse_args( $args, $default_args );
195
+
196
+ $base = $args['base'];
197
+ $unit_product = $args['products'];
198
+
199
+ $product_base = $base;
200
+
201
+ if ( empty( $unit_product ) ) {
202
+ // Set base multiplicator to 1
203
+ $base = 1;
204
+ } else {
205
+ $product_base = $unit_product;
206
+ }
207
+
208
+ $prices = array();
209
+
210
+ // Do not recalculate if unit base and/or product is empty
211
+ if ( 0 == $product_base || 0 == $base ) {
212
+ return $prices;
213
+ }
214
+
215
+ $prices['regular'] = wc_format_decimal( ( $args['regular_price'] / $product_base ) * $base, wc_get_price_decimals() );
216
+ $prices['sale'] = '';
217
+
218
+ if ( ! empty( $args['sale_price'] ) ) {
219
+ $prices['sale'] = wc_format_decimal( ( $args['sale_price'] / $product_base ) * $base, wc_get_price_decimals() );
220
+ }
221
+
222
+ $prices['unit'] = wc_format_decimal( ( $args['price'] / $product_base ) * $base, wc_get_price_decimals() );
223
+
224
+ return apply_filters( 'woocommerce_gzd_recalculated_unit_prices', $prices, $product, $args );
225
  }
includes/wc-gzd-template-functions.php CHANGED
@@ -17,10 +17,25 @@ if ( ! function_exists( 'woocommerce_gzd_template_single_legal_info' ) ) {
17
  */
18
  function woocommerce_gzd_template_single_legal_info() {
19
  global $product;
 
20
  wc_get_template( 'single-product/legal-info.php' );
21
  }
22
  }
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  if ( ! function_exists( 'woocommerce_gzd_template_single_price_unit' ) ) {
25
 
26
  /**
@@ -28,11 +43,48 @@ if ( ! function_exists( 'woocommerce_gzd_template_single_price_unit' ) ) {
28
  */
29
  function woocommerce_gzd_template_single_price_unit() {
30
  global $product;
31
- if ( in_array( $product->get_type(), apply_filters( 'woocommerce_gzd_product_types_supporting_unit_prices', array( 'simple', 'external', 'variable' ) ) ) )
 
32
  wc_get_template( 'single-product/price-unit.php' );
 
33
  }
34
  }
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  if ( ! function_exists( 'woocommerce_gzd_template_single_shipping_costs_info' ) ) {
37
 
38
  /**
@@ -53,6 +105,20 @@ if ( ! function_exists( 'woocommerce_gzd_template_single_delivery_time_info' ) )
53
  }
54
  }
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  if ( ! function_exists( 'woocommerce_gzd_template_single_tax_info' ) ) {
57
 
58
  /**
@@ -68,7 +134,17 @@ if ( ! function_exists( 'woocommerce_gzd_template_single_product_units' ) ) {
68
  function woocommerce_gzd_template_single_product_units() {
69
  wc_get_template( 'single-product/units.php' );
70
  }
 
71
 
 
 
 
 
 
 
 
 
 
72
  }
73
 
74
  if ( ! function_exists( 'woocommerce_gzd_template_small_business_info' ) ) {
17
  */
18
  function woocommerce_gzd_template_single_legal_info() {
19
  global $product;
20
+
21
  wc_get_template( 'single-product/legal-info.php' );
22
  }
23
  }
24
 
25
+ if ( ! function_exists( 'woocommerce_gzd_template_grouped_single_legal_info' ) ) {
26
+
27
+ /**
28
+ * Single Product delivery time info
29
+ */
30
+ function woocommerce_gzd_template_grouped_single_legal_info( $html, $grouped_child ) {
31
+ ob_start();
32
+ wc_get_template( 'single-product/legal-info.php' );
33
+ $legal_html = ob_get_clean();
34
+
35
+ return $html . $legal_html;
36
+ }
37
+ }
38
+
39
  if ( ! function_exists( 'woocommerce_gzd_template_single_price_unit' ) ) {
40
 
41
  /**
43
  */
44
  function woocommerce_gzd_template_single_price_unit() {
45
  global $product;
46
+
47
+ if ( in_array( $product->get_type(), apply_filters( 'woocommerce_gzd_product_types_supporting_unit_prices', array( 'simple', 'external', 'variable', 'grouped' ) ) ) ) {
48
  wc_get_template( 'single-product/price-unit.php' );
49
+ }
50
  }
51
  }
52
 
53
+ if ( ! function_exists( 'woocommerce_gzd_template_single_setup_global_product' ) ) {
54
+
55
+ function woocommerce_gzd_template_single_setup_global_product() {
56
+ global $product, $wc_gzd_global_product;
57
+
58
+ $wc_gzd_global_product = $product;
59
+ }
60
+ }
61
+
62
+ if ( ! function_exists( 'woocommerce_gzd_template_grouped_single_price_unit' ) ) {
63
+
64
+ /**
65
+ * Grouped Product price per unit.
66
+ * If grouped parent has unit price, recalculate child unit prices with grouped parent unit base.
67
+ */
68
+ function woocommerce_gzd_template_grouped_single_price_unit( $html, $grouped_child ) {
69
+ global $wc_gzd_global_product;
70
+
71
+ $gzd_product = wc_gzd_get_gzd_product( $wc_gzd_global_product );
72
+ $gzd_child = wc_gzd_get_gzd_product( $grouped_child );
73
+
74
+ if( $gzd_product->has_unit() ) {
75
+ $gzd_child->recalculate_unit_price( array(
76
+ 'base' => $gzd_product->get_unit_base_raw(),
77
+ ) );
78
+ }
79
+
80
+ ob_start();
81
+ wc_get_template( 'single-product/price-unit.php', array( 'gzd_product' => $gzd_child ) );
82
+ $unit_html = ob_get_clean();
83
+
84
+ return $html . $unit_html;
85
+ }
86
+ }
87
+
88
  if ( ! function_exists( 'woocommerce_gzd_template_single_shipping_costs_info' ) ) {
89
 
90
  /**
105
  }
106
  }
107
 
108
+ if ( ! function_exists( 'woocommerce_gzd_template_grouped_single_delivery_time_info' ) ) {
109
+
110
+ /**
111
+ * Grouped single product delivery time info
112
+ */
113
+ function woocommerce_gzd_template_grouped_single_delivery_time_info( $html, $grouped_child ) {
114
+ ob_start();
115
+ wc_get_template( 'single-product/delivery-time-info.php' );
116
+ $legal_html = ob_get_clean();
117
+
118
+ return $html . $legal_html;
119
+ }
120
+ }
121
+
122
  if ( ! function_exists( 'woocommerce_gzd_template_single_tax_info' ) ) {
123
 
124
  /**
134
  function woocommerce_gzd_template_single_product_units() {
135
  wc_get_template( 'single-product/units.php' );
136
  }
137
+ }
138
 
139
+ if ( ! function_exists( 'woocommerce_gzd_template_grouped_single_product_units' ) ) {
140
+
141
+ function woocommerce_gzd_template_grouped_single_product_units( $html, $grouped_child ) {
142
+ ob_start();
143
+ wc_get_template( 'single-product/units.php' );
144
+ $legal_html = ob_get_clean();
145
+
146
+ return $html . $legal_html;
147
+ }
148
  }
149
 
150
  if ( ! function_exists( 'woocommerce_gzd_template_small_business_info' ) ) {
includes/wc-gzd-template-hooks.php CHANGED
@@ -17,6 +17,7 @@ if ( get_option( 'woocommerce_gzd_display_digital_delivery_time_text' ) !== '' )
17
  add_filter( 'woocommerce_germanized_empty_delivery_time_text', 'woocommerce_gzd_template_digital_delivery_time_text', 10, 2 );
18
 
19
  add_filter( 'woocommerce_get_price_html', 'woocommerce_gzd_template_sale_price_label_html', 50, 2 );
 
20
  // WC pre 2.7
21
  add_filter( 'woocommerce_get_variation_price_html', 'woocommerce_gzd_template_sale_price_label_html', 50, 2 );
22
 
@@ -24,16 +25,27 @@ add_filter( 'woocommerce_get_variation_price_html', 'woocommerce_gzd_template_sa
24
  * Single Product
25
  */
26
  foreach( wc_gzd_get_legal_product_notice_types_by_location( 'single' ) as $type => $notice ) {
27
- add_action( $notice['filter'], $notice['callback'], $notice['priority'] );
 
 
 
 
28
  }
29
 
 
 
 
30
  add_filter( 'woocommerce_available_variation', 'woocommerce_gzd_add_variation_options', 0, 3 );
31
 
32
  /**
33
  * Product Loop Items
34
  */
35
  foreach( wc_gzd_get_legal_product_notice_types_by_location( 'loop' ) as $type => $notice ) {
36
- add_action( $notice['filter'], $notice['callback'], $notice['priority'] );
 
 
 
 
37
  }
38
 
39
  if ( get_option( 'woocommerce_gzd_display_listings_add_to_cart' ) == 'no' ) {
17
  add_filter( 'woocommerce_germanized_empty_delivery_time_text', 'woocommerce_gzd_template_digital_delivery_time_text', 10, 2 );
18
 
19
  add_filter( 'woocommerce_get_price_html', 'woocommerce_gzd_template_sale_price_label_html', 50, 2 );
20
+
21
  // WC pre 2.7
22
  add_filter( 'woocommerce_get_variation_price_html', 'woocommerce_gzd_template_sale_price_label_html', 50, 2 );
23
 
25
  * Single Product
26
  */
27
  foreach( wc_gzd_get_legal_product_notice_types_by_location( 'single' ) as $type => $notice ) {
28
+ if ( $notice['is_action'] ) {
29
+ add_action( $notice['filter'], $notice['callback'], $notice['priority'], $notice['params'] );
30
+ } else {
31
+ add_filter( $notice['filter'], $notice['callback'], $notice['priority'], $notice['params'] );
32
+ }
33
  }
34
 
35
+ // Make sure to add a global product object to allow getting the grouped parent product within child display
36
+ add_action( 'woocommerce_before_add_to_cart_form', 'woocommerce_gzd_template_single_setup_global_product' );
37
+
38
  add_filter( 'woocommerce_available_variation', 'woocommerce_gzd_add_variation_options', 0, 3 );
39
 
40
  /**
41
  * Product Loop Items
42
  */
43
  foreach( wc_gzd_get_legal_product_notice_types_by_location( 'loop' ) as $type => $notice ) {
44
+ if ( $notice['is_action'] ) {
45
+ add_action( $notice['filter'], $notice['callback'], $notice['priority'], $notice['params'] );
46
+ } else {
47
+ add_filter( $notice['filter'], $notice['callback'], $notice['priority'], $notice['params'] );
48
+ }
49
  }
50
 
51
  if ( get_option( 'woocommerce_gzd_display_listings_add_to_cart' ) == 'no' ) {
readme.txt CHANGED
@@ -5,7 +5,7 @@ Requires at least: 3.8
5
  Tested up to: 5.2
6
  WC requires at least: 2.4
7
  WC tested up to: 3.6
8
- Stable tag: 2.3.0
9
  Requires PHP: 5.3
10
  License: GPLv3
11
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
@@ -181,6 +181,15 @@ Bug reports may be filed via our [GitHub repository](https://github.com/vendider
181
 
182
  == Changelog ==
183
 
 
 
 
 
 
 
 
 
 
184
  = 2.3.0 =
185
  * Feature: Better legal hook placement via wc_gzd_get_legal_*_notice_types_by_location
186
  * Feature: Added options to enable/disable legal info within cart, checkout and mini cart
5
  Tested up to: 5.2
6
  WC requires at least: 2.4
7
  WC tested up to: 3.6
8
+ Stable tag: 2.3.1
9
  Requires PHP: 5.3
10
  License: GPLv3
11
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
181
 
182
  == Changelog ==
183
 
184
+ = 2.3.1 =
185
+ * Feature: Added better fee/shipping costs calculation to order tax recalculation
186
+ * Feature: Grouped products: Unit price support if all children share the same unit
187
+ * Feature: Grouped products: Show legal info per item
188
+ * Improvement: Activate parcel shop delivery address format as soon as post number is added to the order
189
+ * Improvement: Force customer registration redirect for customer that have not yet been activated (DOI)
190
+ * Improvement: Added _legal_text post meta to wpml config
191
+ * Tweak: Do not watch for product updates within checkout (causes problem with WPML)
192
+
193
  = 2.3.0 =
194
  * Feature: Better legal hook placement via wc_gzd_get_legal_*_notice_types_by_location
195
  * Feature: Added options to enable/disable legal info within cart, checkout and mini cart
templates/single-product/price-unit.php CHANGED
@@ -10,8 +10,14 @@
10
  if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
11
 
12
  global $product;
 
 
 
 
 
 
13
  ?>
14
 
15
- <?php if ( wc_gzd_get_gzd_product( $product )->has_unit() ) : ?>
16
- <p class="price price-unit smaller"><?php echo wc_gzd_get_gzd_product( $product )->get_unit_html(); ?></p>
17
  <?php endif; ?>
10
  if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
11
 
12
  global $product;
13
+
14
+ $_product = $product;
15
+
16
+ if ( isset( $gzd_product ) ) {
17
+ $_product = $gzd_product;
18
+ }
19
  ?>
20
 
21
+ <?php if ( wc_gzd_get_gzd_product( $_product )->has_unit() ) : ?>
22
+ <p class="price price-unit smaller wc-gzd-additional-info"><?php echo wc_gzd_get_gzd_product( $_product )->get_unit_html(); ?></p>
23
  <?php endif; ?>
templates/single-product/units.php CHANGED
@@ -14,4 +14,6 @@ global $product;
14
 
15
  <?php if ( wc_gzd_get_gzd_product( $product )->has_product_units() ) : ?>
16
  <p class="wc-gzd-additional-info product-units-wrapper product-units"><?php echo wc_gzd_get_gzd_product( $product )->get_product_units_html(); ?></p>
 
 
17
  <?php endif; ?>
14
 
15
  <?php if ( wc_gzd_get_gzd_product( $product )->has_product_units() ) : ?>
16
  <p class="wc-gzd-additional-info product-units-wrapper product-units"><?php echo wc_gzd_get_gzd_product( $product )->get_product_units_html(); ?></p>
17
+ <?php elseif ( $product->is_type( 'variable' ) ) : ?>
18
+ <p class="wc-gzd-additional-info product-units-wrapper product-units"></p>
19
  <?php endif; ?>
woocommerce-germanized.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Germanized for WooCommerce
4
  * Plugin URI: https://www.vendidero.de/woocommerce-germanized
5
  * Description: Germanized for WooCommerce extends WooCommerce to become a legally compliant store in the german market.
6
- * Version: 2.3.0
7
  * Author: Vendidero
8
  * Author URI: https://vendidero.de
9
  * Requires at least: 3.8
@@ -31,7 +31,7 @@ final class WooCommerce_Germanized {
31
  *
32
  * @var string
33
  */
34
- public $version = '2.3.0';
35
 
36
  /**
37
  * Single instance of WooCommerce Germanized Main Class
@@ -337,6 +337,7 @@ final class WooCommerce_Germanized {
337
 
338
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin.php';
339
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-welcome.php';
 
340
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-notices.php';
341
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-customer.php';
342
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-legal-checkboxes.php';
3
  * Plugin Name: Germanized for WooCommerce
4
  * Plugin URI: https://www.vendidero.de/woocommerce-germanized
5
  * Description: Germanized for WooCommerce extends WooCommerce to become a legally compliant store in the german market.
6
+ * Version: 2.3.2
7
  * Author: Vendidero
8
  * Author URI: https://vendidero.de
9
  * Requires at least: 3.8
31
  *
32
  * @var string
33
  */
34
+ public $version = '2.3.1';
35
 
36
  /**
37
  * Single instance of WooCommerce Germanized Main Class
337
 
338
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin.php';
339
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-welcome.php';
340
+ include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-order.php';
341
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-notices.php';
342
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-customer.php';
343
  include_once WC_GERMANIZED_ABSPATH . 'includes/admin/class-wc-gzd-admin-legal-checkboxes.php';
wpml-config.xml CHANGED
@@ -15,6 +15,7 @@
15
  <custom-field action="copy">_differential_taxation</custom-field>
16
  <custom-field action="translate">_ts_mpn</custom-field>
17
  <custom-field action="translate">_ts_gtin</custom-field>
 
18
  </custom-fields>
19
  <taxonomies>
20
  <taxonomy translate="1">product_price_label</taxonomy>
15
  <custom-field action="copy">_differential_taxation</custom-field>
16
  <custom-field action="translate">_ts_mpn</custom-field>
17
  <custom-field action="translate">_ts_gtin</custom-field>
18
+ <custom-field action="translate">_legal_text</custom-field>
19
  </custom-fields>
20
  <taxonomies>
21
  <taxonomy translate="1">product_price_label</taxonomy>