<?php
/**
* Base class for hook handlers.
*
* @package Stripe\StripeTaxForWooCommerce\WordPress
*/
namespace Stripe\StripeTaxForWooCommerce\WordPress;
defined( 'ABSPATH' ) || exit;
use Stripe\StripeTaxForWooCommerce\StripeTax_Options;
use Stripe\StripeTaxForWooCommerce\Stripe\StripeTaxLogger;
use Stripe\StripeTaxForWooCommerce\Stripe\StripeTaxPluginHelper;
use Stripe\StripeTaxForWooCommerce\Stripe\Tax_Calculation\Input_Exception;
use Throwable;
/**
* Base class for hook handlers.
*/
abstract class Hook_Handlers {
const ACTIONS = array();
const FILTERS = array();
const ACTIVATION_OPTIONS = array();
/**
* Whether the current request has failed.
*
* @var bool
*/
protected static $current_request_failed = false;
/**
* Stores a human-readable error for the current request failure.
*
* @var string
*/
protected static $current_request_error_message = '';
/**
* Register action and filter hook handlers
*/
public static function register_hook_handlers(): void {
static::register_hook_handler_by_names( 'action', static::ACTIONS );
static::register_hook_handler_by_names( 'filter', static::FILTERS );
}
/**
* Unegisters action and filter hook handlers
*/
public static function unregister_hook_handlers(): void {
static::unregister_hook_handler_by_names( 'action', static::ACTIONS );
static::unregister_hook_handler_by_names( 'filter', static::FILTERS );
}
/**
* Register hook handlers by their type and name
*
* @param string $hook_type Filter or action.
* @param string|string[] $hook_names Filter or action names.
*/
protected static function register_hook_handler_by_names( $hook_type, $hook_names ) {
$registration_function_name = 'add_' . $hook_type;
foreach ( $hook_names as $hook_name ) {
$registration_function_name(
'woocommerce_' . $hook_name,
array( static::class, $hook_name ),
100,
4
);
}
}
/**
* Unegister hook handlers by their type and name
*
* @param string $hook_type Filter or action.
* @param string|string[] $hook_names Filter or action names.
*/
protected static function unregister_hook_handler_by_names( $hook_type, $hook_names ) {
$unregistration_function_name = 'remove_' . $hook_type;
foreach ( $hook_names as $hook_name ) {
$unregistration_function_name(
'woocommerce_' . $hook_name,
array( static::class, $hook_name ),
100
);
}
}
/**
* Shows if handles should be enabled
*/
public static function is_enabled() {
if ( ! Options::is_live_mode_enabled() || self::is_current_request_failed() || ! wc_tax_enabled() ) {
return false;
}
return true;
}
/**
* Handles errors.
*
* @param throwable $err The error.
*/
protected static function on_error( $err ) {
StripeTaxLogger::log_info( $err->getMessage() );
static::$current_request_error_message = static::get_customer_safe_error_message( $err );
if ( is_admin() ) {
$message = StripeTaxPluginHelper::format_api_error_message( $err );
static::show_admin_error( $message );
}
}
/**
* Given a throwable object, formats and outputs an error mesage
*
* @param object $err The throwable object.
*/
protected static function show_admin_error( $err ) {
$message = $err instanceof \Throwable ? $err->getMessage() : (string) $err;
if ( wp_doing_ajax() ) {
// ✅ Verify nonce BEFORE using $_REQUEST.
$security = isset( $_REQUEST['security'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['security'] ) ) : '';
if ( ! $security || ! wp_verify_nonce( $security, 'order-item' ) ) {
StripeTaxLogger::log_info( 'StripeTax AJAX: invalid/missing nonce in show_admin_error' );
return;
}
$order_id = isset( $_REQUEST['order_id'] )
? absint( wp_unslash( $_REQUEST['order_id'] ) )
: 0;
if ( $order_id ) {
update_post_meta( $order_id, '_stripe_tax_last_error', wp_strip_all_tags( $message ) );
} else {
$action = isset( $_REQUEST['action'] )
? sanitize_key( wp_unslash( $_REQUEST['action'] ) )
: 'none';
StripeTaxLogger::log_info( 'StripeTax AJAX: missing order_id (action=' . $action . ')' );
}
return;
}
echo '<div class="notice notice-error"><p><strong>'
. esc_html__( 'Stripe Tax:', 'stripe-tax-for-woocommerce' )
. '</strong> ' . esc_html( $message ) . '</p></div>';
}
/**
* Handles generic errors.
*
* @param throwable $err The error.
*/
protected static function on_generic_error( $err ) {
StripeTaxLogger::log_error( $err->getMessage() );
static::$current_request_error_message = static::get_customer_safe_error_message( $err );
if ( is_admin() ) {
$message = StripeTaxPluginHelper::format_api_error_message( $err );
static::show_admin_error( $message );
}
}
/**
* Sets the failure state for the current request.
*
* This flag is used to track whether tax calculation failed during
* the current checkout request.
*
* @param bool $status True to mark the current request as failed.
*
* @return void
*/
protected static function set_current_request_failed( $status ): void {
static::$current_request_failed = (bool) $status;
if ( ! static::$current_request_failed ) {
static::$current_request_error_message = '';
}
}
/**
* Checks whether the current request has been marked as failed.
*
* This can be used during checkout processing to determine whether
* tax calculation failed earlier in the request.
*
* @return bool True if the current request failed, false otherwise.
*/
public static function is_current_request_failed(): bool {
return static::$current_request_failed;
}
/**
* Returns the error message associated with current request failure.
*
* @return string
*/
public static function get_current_request_error_message(): string {
return static::$current_request_error_message;
}
/**
* Returns a checkout-safe error message for customers.
*
* @param Throwable $err The captured exception.
*
* @return string
*/
protected static function get_customer_safe_error_message( Throwable $err ): string {
if ( $err instanceof Input_Exception ) {
return wp_strip_all_tags( (string) $err->getMessage() );
}
return '';
}
}