Zaokrouhlení celkové ceny objednávky ve WooCommerce

Možná jste se tím již setkali. Chcete zobrazovat cenu produktů na dvě desetiná čísla, ale celkovou cenu na objednávce a faktuře potřebujete mít zaokrouhleno na celé číslo. WooCommerce sice umožňuje nastavit počet desetin, ale globálně pro celý eshop.

Dnešní článek bude obsahovat trochu více kódu, ale ukážeme si, jak upravit zobrazování celkového součtu v košíku, checkoutu a objednávce.

Co potřebujeme upravit

total

Jak jsem psal výše, chceme zaokrouhlit celkový součet, na celé číslo.

Pokud se podíváme do souboru cart-totals.php ve  složce themes, uvidíme, že o výpis součtu, se stará funkce wc_cart_totals_order_total_html().

Tu najdeme v souboru wc-cart-funcitons.php. A zde narážíme na první problém, Funkce neobsahuje žádné filtry, nebo akce. Pokud se ale pdíváme pozorněji, zjistíme, že o zobrazení celkové ceny se stará zápis WC()->cart->get_total() a pokud se má zobrazit i DPH, je načteno do pole $tax_string_array a pak zobrazeno.

V souboru class-wc-cart.php najdeme zmíněnou metodu get_total a můžeme zajásat, protože tam již máme k dispozici filter. Metoda vypadá takto:

public function get_total() {
         return apply_filters( 'woocommerce_cart_total', wc_price( $this->total ) );
}

Pokud nevíte, co dělá funkce wc_price(), tak ta se stará o výpis zformátované ceny. Zjišťuje, kolik je desetiných míst nastavených, jaká měna, zkrátka vše, co potřebujete k výpisu ceny v šabloně.

Protože máme k dispozici filter pro cart total, upravíme pouze to co dodává funkce wc_price. Vytvoříme so vlastní funkci, která bude identická, jen se bude lišit v

$num_decimals    = absint( get_option( 'woocommerce_price_num_decimals' ) );
 
$num_decimals    = absint( 0 );

Celá funkce:

function custom_wc_price( $price, $args = array() ) {
 
  extract( shortcode_atts( array(
		'ex_tax_label' 	=> '0'
	), $args ) );
 
	$return          = '';
	$num_decimals    = absint( 0 );
	$currency        = isset( $args['currency'] ) ? $args['currency'] : '';
	$currency_symbol = get_woocommerce_currency_symbol($currency);
	$decimal_sep     = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_decimal_sep' ) ), ENT_QUOTES );
	$thousands_sep   = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_thousand_sep' ) ), ENT_QUOTES );
 
	if ( $price < 0 ) { $price = $price * -1; $negative = true; } else { $negative = false; } $price = apply_filters( 'raw_woocommerce_price', floatval( $price ) ); $price = apply_filters( 'formatted_woocommerce_price', number_format( $price, $num_decimals, $decimal_sep, $thousands_sep ), $price, $num_decimals, $decimal_sep, $thousands_sep ); if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $num_decimals > 0 ) {
		$price = wc_trim_zeros( $price );
	}
 
	$formatted_price = ( $negative ? '-' : '' ) . sprintf( get_woocommerce_price_format(), $currency_symbol, $price );
	$return          = '<span class="amount">' . $formatted_price . '</span>';
 
	if ( $ex_tax_label &amp;&amp; get_option( 'woocommerce_calc_taxes' ) == 'yes' ) {
		$return .= ' <small>' . WC()-&gt;countries-&gt;ex_tax_or_vat() . '</small>';
	}
 
	return $return;
}

Nyní musíme zaokrouhlenou cenu vložit na příslušné místo pomocí filtru:

add_filter( 'woocommerce_cart_total', 'round_price',999  );
function round_price(){
 
     $rounded = WC()-&gt;cart-&gt;total;
 
     return custom_wc_price( $rounded );
 
  }

Takže nyní se nám zobrazuje v součtu košíku cena bez desetiných míst, ale pokud máte nastaveno zobrazování DPH, tak tax se ještě zobrazuje nezaokrouhlená.
V souboru class-wc-cart.php najdeme metodu get_tax_totals(), která obsahuje filter woocommerce_cart_tax_totals.

Důležitá je pro nás tato řádka:

$tax_totals[ $code ]-&gt;formatted_amount  = wc_price( wc_round_tax_total( $tax_totals[ $code ]-&gt;amount ) );

Protože jsme si již vytvořili ekvivalent funkce wc_price(), zkopírujeme metodu do nové funkce, nahradíme wc_price() a využijeme filter woocommerce_cart_tax_totals, který obsahuje.

add_filter( 'woocommerce_cart_tax_totals', 'round_cart_tax_totals',999  );
function round_cart_tax_totals(){
 
    $taxes  = WC()-&gt;cart-&gt;get_taxes();
			$tax_totals = array();
 
			foreach ( $taxes as $key =&gt; $tax ) {
 
				$code = WC()-&gt;cart-&gt;tax-&gt;get_rate_code( $key );
 
				if ( $code ) {
					if ( ! isset( $tax_totals[ $code ] ) ) {
						$tax_totals[ $code ] = new stdClass();
						$tax_totals[ $code ]-&gt;amount = 0;
					}
 
					$tax_totals[ $code ]-&gt;tax_rate_id       = $key;
					$tax_totals[ $code ]-&gt;is_compound       = WC()-&gt;cart-&gt;tax-&gt;is_compound( $key );
					$tax_totals[ $code ]-&gt;label             = WC()-&gt;cart-&gt;tax-&gt;get_rate_label( $key );
					$tax_totals[ $code ]-&gt;amount           += wc_round_tax_total( $tax );
					$tax_totals[ $code ]-&gt;formatted_amount  = $this-&gt;custom_wc_price( wc_round_tax_total( $tax_totals[ $code ]-&gt;amount ) );
				}
			}
 
      return $tax_totals;
 
 
  }

Tím jsme dosáhli požadovaného výsledku pro zobrazení součtu v košíku a na stránce pokladny. Musíme však ještě vytvořit obdobné úpravy i pro thankyou stránku, pro detail objednávky ve vašem účtu a detailu objednávky v administraci.

Pokud se podíváte do thankyou.php ve složce templates/checkout, uvidíte, že o zobrazení se stará $order->get_formatted_order_total().

Najdeme ve složce includes/abstract/anstract-wc-order.php a v souboru metodu get_formatted_order_total().
Ta vypadá takto:

public function get_formatted_order_total() {
		$formatted_total = wc_price( $this-&gt;get_total(), array( 'currency' =&gt; $this-&gt;get_order_currency() ) );
 
		return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this );
	}

Díky filtru woocommerce_get_formatted_order_total a naší custom_wc_price() upravíme celkový součet:

add_filter( 'woocommerce_get_formatted_order_total', 'custom_get_formatted_order_total',999, 2 );
function custom_get_formatted_order_total($formatted_total, $order) {
 
    $formatted_total = custom_wc_price( $order-&gt;get_total(), array( 'currency' =&gt; $order-&gt;get_order_currency() ) );
 
		return $formatted_total;
}

A máme před sebou poslední krok. Najdeme si v templates/order/order-details.php, kde najdeme:

if ( $totals = $order-&gt;get_order_item_totals() ) foreach ( $totals as $total ) :
	?&gt;

 

<?php endforeach;

Opět se podíváme do abstract-wc-order.php na metodu get_order_item_totals(). V metodě se prochází pole $total_rows, ale nás zajímá pouze to s klíčem order_total. Jeho hodnota vypadá takto:

$total_rows['order_total'] = array(
	'label' =&gt; __( 'Order Total:', 'woocommerce' ),
	'value'	=&gt; $this-&gt;get_formatted_order_total()
);

A protože obsahuje i filter woocommerce_get_order_item_totals, pomocí něj upravíme i hodnotu pole.

add_filter( 'woocommerce_get_order_item_totals', 'custom_get_order_item_totals',999, 2 );
function custom_get_order_item_totals($total_rows, $order){
 
 
    $total_rows['order_total'] = array();
		$total_rows['order_total']['label'] = __( 'Total:', 'woocommerce' );
		$total_rows['order_total']['value']	= $order-&gt;get_formatted_order_total();
 
	  $tax_string_array = array();
    if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) {
 
				foreach ( $order-&gt;get_tax_totals() as $code =&gt; $tax ) {
					$tax_string_array[] = sprintf( '%s %s', $tax-&gt;formatted_amount, $tax-&gt;label );
				}
 
			} else {
				$tax_string_array[] = sprintf( '%s %s', $this-&gt;custom_wc_price( $order-&gt;get_total_tax(), array('currency' =&gt; $order-&gt;get_order_currency()) ), WC()-&gt;countries-&gt;tax_or_vat() );
			}
 
			if ( ! empty( $tax_string_array ) ) {
				$total_rows['order_total']['value'] .= ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) );
		  }
 
 
    return $total_rows;
  }

Tím jsme upravili celkový součet a úpravou $order->get_total_tax(), pomocí filtru woocommerce_order_tax_totals zaokrouhlíme částku za DPH.

add_filter( 'woocommerce_order_tax_totals', 'custom_round_order_tax_totals',999, 2  );
custom_round_order_tax_totals($tax_totals, $order){
 
    $taxes      = $order-&gt;get_items( 'tax' );
		$tax_totals = array();
 
		foreach ( $taxes as $key =&gt; $tax ) {
 
			$code = $tax[ 'name' ];
 
			if ( ! isset( $tax_totals[ $code ] ) ) {
				$tax_totals[ $code ] = new stdClass();
				$tax_totals[ $code ]-&gt;amount = 0;
			}
 
			$tax_totals[ $code ]-&gt;id                = $key;
			$tax_totals[ $code ]-&gt;rate_id           = $tax['rate_id'];
			$tax_totals[ $code ]-&gt;is_compound       = $tax[ 'compound' ];
			$tax_totals[ $code ]-&gt;label             = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
			$tax_totals[ $code ]-&gt;amount           += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
			$tax_totals[ $code ]-&gt;formatted_amount  = custom_wc_price( wc_round_tax_total( $tax_totals[ $code ]-&gt;amount ), array('currency' =&gt; $order-&gt;get_order_currency()) );
		}
 
		return $tax_totals;
 
 
  }

Jak můžete vidět, opět jsme použili funkci custom_wc_price. Úpravy, které ovlivní zobrazování celkového součtu v objednávce na front endu, upraví i zobrazení celkové ceny v administraci objednávky.

Těším se u dalšího návodu.

About The Author

Zajímá mne Wordpress, responsivní šablony a zkrátka vše kolem tohoto skvělého redakčního systému.

Související články

5 Comments

  1. Marek Klusák

    Skvělý návod, díky moc! Je tam drobná chybka, v jednom snippetu je $this->custom_wc_price() … to $this způsobí problémy.

    Teď už jen dopátrat, jak donutit košík zaokrouhlit i mezisoučet …

    Odpověď
    1. Musilda

      To bych nedělal. Mohlo by pak docházet k drobným odchylkám při výpočtu DPH, často se s tím potýkám.

      Odpověď
      1. Martin

        Super návod. Zrovna to teď řeším.
        Hlásí mi to ale stejnou chybu u $this ($this->custom_wc_price() …)
        Máte někdo řešení?

        Odpověď
  2. Marek Klusák

    No, v mé nynější implementaci jsou ceny produktů zadány bez DPH, a výsledné částky dopočteny … jenže tím pádem až na haléře. Což klient nechce, takže se tyto ceny s DPH zaokrouhlují. A na souhrnu objednávky to pak vypadá třeba Produkt A 200 Kč, Produkt B 300 Kč, Mezisoučet 500,25 Kč. … což je taky problém.

    Odpověď

Přidejte komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *