<?php
/**
* Templates class for Klarna checkout.
*
* @package Klarna_Checkout/Classes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* KCO_Templates class.
*/
class KCO_Templates {
/**
* The KCO plugin settings.
*
* @var array|false
*/
private $settings;
/**
* The reference the *Singleton* instance of this class.
*
* @var KCO_Templates
*/
protected static $instance;
/**
* Returns the *Singleton* instance of this class.
*
* @return self::$instance The *Singleton* instance.
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Plugin actions.
*/
public function __construct() {
$this->settings = get_option( 'woocommerce_kco_settings' );
// If the redirect flow is selected, we do not need to load the template.
if ( 'redirect' === ( $this->settings['checkout_flow'] ?? 'embedded' ) ) {
return;
}
// Override template if Klarna Checkout page.
add_filter( 'wc_get_template', array( $this, 'override_template' ), 999, 2 );
add_action( 'wp_footer', array( $this, 'check_that_kco_template_has_loaded' ) );
// Template hooks.
add_action( 'kco_wc_after_order_review', 'kco_wc_add_extra_checkout_fields', 10 );
add_action( 'kco_wc_after_order_review', 'kco_wc_show_another_gateway_button', 20 );
add_action( 'kco_wc_before_snippet', 'kco_wc_prefill_consent', 10 );
add_action( 'kco_wc_before_snippet', array( $this, 'add_wc_form' ), 10 ); // @TODO Look into changing this to kco_wc_after_wrapper later.
add_action( 'kco_wc_before_snippet', array( $this, 'add_review_order_before_submit' ), 15 );
// Unrequire WooCommerce Billing State field.
add_filter( 'woocommerce_billing_fields', array( $this, 'kco_wc_unrequire_wc_billing_state_field' ) );
// Unrequire WooCommerce Shipping State field.
add_filter( 'woocommerce_shipping_fields', array( $this, 'kco_wc_unrequire_wc_shipping_state_field' ) );
// Adds the required CSS classes for the checkout layout.
add_filter( 'body_class', array( $this, 'add_body_class' ) );
}
/**
* Override checkout form template if Klarna Checkout is the selected payment method.
*
* @param string $template Template.
* @param string $template_name Template name.
*
* @return string
*/
public function override_template( $template, $template_name ) {
if ( is_checkout() ) {
$confirm = filter_input( INPUT_GET, 'confirm', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
// Don't display KCO template if we have a cart that doesn't needs payment.
if ( apply_filters( 'kco_check_if_needs_payment', true ) && ! is_wc_endpoint_url( 'order-pay' ) ) {
if ( ! WC()->cart->needs_payment() ) {
return $template;
}
}
// Don't use KCO template for pay for order orders.
if ( is_wc_endpoint_url( 'order-pay' ) ) {
return $template;
}
// Klarna Checkout.
if ( 'checkout/form-checkout.php' === $template_name ) {
$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
if ( locate_template( 'woocommerce/klarna-checkout.php' ) ) {
$klarna_checkout_template = locate_template( 'woocommerce/klarna-checkout.php' );
} else {
$klarna_checkout_template = apply_filters( 'kco_locate_checkout_template', KCO_WC_PLUGIN_PATH . '/templates/klarna-checkout.php', $template_name );
}
// Klarna checkout page.
if ( array_key_exists( 'kco', $available_gateways ) ) {
// If chosen payment method exists.
if ( 'kco' === WC()->session->get( 'chosen_payment_method' ) ) {
if ( empty( $confirm ) ) {
$template = $klarna_checkout_template;
}
}
// If chosen payment method does not exist and KCO is the first gateway.
if ( null === WC()->session->get( 'chosen_payment_method' ) || '' === WC()->session->get( 'chosen_payment_method' ) ) {
reset( $available_gateways );
if ( 'kco' === key( $available_gateways ) ) {
if ( empty( $confirm ) ) {
$template = $klarna_checkout_template;
}
}
}
// If another gateway is saved in session, but has since become unavailable.
if ( WC()->session->get( 'chosen_payment_method' ) ) {
if ( ! array_key_exists( WC()->session->get( 'chosen_payment_method' ), $available_gateways ) ) {
reset( $available_gateways );
if ( 'kco' === key( $available_gateways ) ) {
if ( empty( $confirm ) ) {
$template = $klarna_checkout_template;
}
}
}
}
}
}
}
return $template;
}
/**
* Redirect customer to cart page if Klarna Checkout is the selected (or first)
* payment method but the KCO template file hasn't been loaded.
*/
public function check_that_kco_template_has_loaded() {
// Exit early.
if ( ! is_checkout() ) {
return;
}
if ( array_key_exists( 'kco', WC()->payment_gateways->get_available_payment_gateways() ) && 'kco' === kco_wc_get_selected_payment_method() && ( method_exists( WC()->cart, 'needs_payment' ) && WC()->cart->needs_payment() ) ) {
// Get checkout object.
$checkout = WC()->checkout();
$settings = get_option( 'woocommerce_kco_settings' );
$enabled = ( 'yes' === $settings['enabled'] ) ? true : false;
// Bail if this is KCO confirmation page, order received page, KCO page (kco_wc_show_snippet has run), user is not logged and registration is disabled or if woocommerce_cart_has_errors has run.
if ( is_kco_confirmation()
|| is_wc_endpoint_url( 'order-received' )
|| did_action( 'kco_wc_show_snippet' )
|| ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() )
|| did_action( 'woocommerce_cart_has_errors' )
|| isset( $_GET['change_payment_method'] ) // phpcs:ignore
|| ! $enabled ) {
return;
}
wc_add_notice( __( 'Klarna Checkout is not available. Please choose a different payment option or contact the store for assistance.', 'klarna-checkout-for-woocommerce' ), 'error' );
$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
// Do not redirect if KCO is the only available gateway to prevent infinite loop.
if ( 1 === count( $available_gateways ) ) {
return;
}
// Select the second available gateway.
$first_gateway = reset( $available_gateways );
if ( 'kco' !== $first_gateway->id ) {
WC()->session->set( 'chosen_payment_method', $first_gateway->id );
} else {
$second_gateway = next( $available_gateways );
WC()->session->set( 'chosen_payment_method', $second_gateway->id );
}
WC()->payment_gateways()->set_current_gateway( $available_gateways );
wp_safe_redirect( wc_get_checkout_url() );
exit;
}
}
/**
* Adds the WC form and other fields to the checkout page.
*
* @return void
*/
public function add_wc_form() {
?>
<div aria-hidden="true" id="kco-wc-form" style="position:absolute; top:-99999px; left:-99999px;">
<?php do_action( 'woocommerce_checkout_billing' ); ?>
<?php do_action( 'woocommerce_checkout_shipping' ); ?>
<div id="kco-nonce-wrapper">
<?php
if ( version_compare( WOOCOMMERCE_VERSION, '3.4', '<' ) ) {
wp_nonce_field( 'woocommerce-process_checkout' );
} else {
wp_nonce_field( 'woocommerce-process_checkout', 'woocommerce-process-checkout-nonce' );
}
wc_get_template( 'checkout/terms.php' );
?>
</div>
<input id="payment_method_kco" type="radio" class="input-radio" name="payment_method" value="kco" checked="checked" /> </div>
<?php
}
/**
* Unrequire WC billing state field.
*
* @param array $fields WC billing fields.
* @return array $fields WC billing fields.
*/
public function kco_wc_unrequire_wc_billing_state_field( $fields ) {
// Unrequire if chosen payment method is Klarna Checkout.
if ( null !== WC()->session && method_exists( WC()->session, 'get' ) &&
WC()->session->get( 'chosen_payment_method' ) &&
'kco' === WC()->session->get( 'chosen_payment_method' )
) {
$fields['billing_state']['required'] = false;
}
return $fields;
}
/**
* Unrequire WC shipping state field.
*
* @param array $fields WC shipping fields.
* @return array $fields WC shipping fields.
*/
public function kco_wc_unrequire_wc_shipping_state_field( $fields ) {
// Unrequire if chosen payment method is Klarna Checkout.
if ( null !== WC()->session && method_exists( WC()->session, 'get' ) &&
WC()->session->get( 'chosen_payment_method' ) &&
'kco' === WC()->session->get( 'chosen_payment_method' )
) {
$fields['shipping_state']['required'] = false;
}
return $fields;
}
/**
* Triggers WC action.
*/
public function add_review_order_before_submit() {
do_action( 'woocommerce_review_order_before_submit' );
}
/**
* Add checkout page body class, depending on checkout page layout settings.
*
* @param array $class CSS classes used in body tag.
* @return array The same input array with the addition of our custom classes.
*/
public function add_body_class( $class ) {
if ( ! is_checkout() || is_wc_endpoint_url( 'order-received' ) ) {
return $class;
}
if ( method_exists( WC()->cart, 'needs_payment' ) && ! WC()->cart->needs_payment() ) {
return $class;
}
$settings = get_option( 'woocommerce_kco_settings' );
$checkout_layout = $settings['checkout_layout'] ?? 'two_column_right';
$first_gateway = '';
if ( WC()->session->get( 'chosen_payment_method' ) ) {
$first_gateway = WC()->session->get( 'chosen_payment_method' );
} else {
$available_payment_gateways = WC()->payment_gateways->get_available_payment_gateways();
reset( $available_payment_gateways );
$first_gateway = key( $available_payment_gateways );
}
if ( 'kco' === $first_gateway && 'two_column_left' === $checkout_layout ) {
$class[] = 'kco-two-column-left';
}
if ( 'kco' === $first_gateway && 'two_column_left_sf' === $checkout_layout ) {
$class[] = 'kco-two-column-left-sf';
}
if ( 'kco' === $first_gateway && 'one_column_checkout' === $checkout_layout ) {
$class[] = 'kco-one-selected';
}
return $class;
}
}
KCO_Templates::get_instance();