Done !
| Server IP : 46.105.57.169 / Your IP : 216.73.216.67 Web Server : Apache System : Linux webm002.cluster120.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64 User : verseaumee ( 152031) PHP Version : 8.5.7 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/verseaumee/blueversion/wp-content/plugins/coinbase-commerce/ |
Upload File : |
<?php // phpcs:disable
/**
* Coinbase Commerce Payment Gateway.
*
* Provides a Coinbase Commerce Payment Gateway.
*
* @class WC_Gateway_Coinbase
* @extends WC_Payment_Gateway
* @since 1.0.0
* @package WooCommerce/Classes/Payment
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Gateway_Coinbase Class.
*/
class WC_Gateway_Coinbase extends WC_Payment_Gateway {
/**
* Log_enabled - whether or not logging is enabled
*
* @var bool Whether or not logging is enabled
*/
public static $log_enabled = false;
/**
* WC_Logger Logger instance
*
* @var WC_Logger Logger instance
* */
public static $log = false;
/**
* Constructor for the gateway.
*/
public function __construct() {
$this->id = 'coinbase';
$this->has_fields = false;
$this->order_button_text = __( 'Proceed to Coinbase', 'coinbase' );
$this->method_title = __( 'Coinbase', 'coinbase' );
$this->method_description = '<p>' .
// translators: Introduction text at top of Coinbase Commerce settings page.
__( 'A payment gateway that sends your customers to Coinbase Commerce to pay with cryptocurrency.', 'coinbase' )
. '</p><p>' .
sprintf(
// translators: Introduction text at top of Coinbase Commerce settings page. Includes external URL.
__( 'If you do not currently have a Coinbase Commerce account, you can set one up here: %s', 'coinbase' ),
'<a target="_blank" href="https://commerce.coinbase.com/">https://commerce.coinbase.com/</a>'
);
// Timeout after 3 days. Default to 3 days as pending Bitcoin txns
// are usually forgotten after 2-3 days.
$this->timeout = ( new WC_DateTime() )->sub( new DateInterval( 'P3D' ) );
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define user set variables.
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->debug = 'yes' === $this->get_option( 'debug', 'no' );
self::$log_enabled = $this->debug;
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', array( $this, '_custom_query_var' ), 10, 2 );
add_action( 'woocommerce_api_wc_gateway_coinbase', array( $this, 'handle_webhook' ) );
}
/**
* Logging method.
*
* @param string $message Log message.
* @param string $level Optional. Default 'info'.
* emergency|alert|critical|error|warning|notice|info|debug
*/
public static function log( $message, $level = 'info' ) {
if ( self::$log_enabled ) {
if ( empty( self::$log ) ) {
self::$log = wc_get_logger();
}
self::$log->log( $level, $message, array( 'source' => 'coinbase' ) );
}
}
/**
* Get gateway icon.
*
* @return string
*/
public function get_icon() {
if ( $this->get_option( 'show_icons' ) === 'no' ) {
return '';
}
$image_path = plugin_dir_path( __FILE__ ) . 'assets/images';
$icon_html = '';
$methods = get_option( 'coinbase_payment_methods', array( 'bitcoin', 'bitcoincash', 'dai', 'ethereum', 'litecoin', 'dogecoin', 'usdc', 'usdt', 'ape', 'shib' ) );
// Load icon for each available payment method.
foreach ( $methods as $m ) {
$path = realpath( $image_path . '/' . $m . '.png' );
if ( $path && dirname( $path ) === $image_path && is_file( $path ) ) {
$url = WC_HTTPS::force_https_url( plugins_url( '/assets/images/' . $m . '.png', __FILE__ ) );
$icon_html .= '<img width="26" src="' . esc_attr( $url ) . '" alt="' . esc_attr__( $m, 'coinbase' ) . '" />';
}
}
/** DOCBLOCK - Makes linter happy.
*
* @since today
*/
return apply_filters( 'woocommerce_gateway_icon', $icon_html, $this->id );
}
/**
* Initialise Gateway Settings Form Fields.
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable Coinbase Commerce Payment', 'coinbase' ),
'default' => 'yes',
),
'title' => array(
'title' => __( 'Title', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Ethereum and other cryptocurrencies', 'coinbase' ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', 'woocommerce' ),
'type' => 'text',
'desc_tip' => true,
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Pay with Ethereum or other cryptocurrencies.', 'coinbase' ),
),
'api_key' => array(
'title' => __( 'API Key', 'coinbase' ),
'type' => 'text',
'default' => '',
'description' => sprintf(
// translators: Description field for API on settings page. Includes external link.
__(
'You can manage your API keys within the Coinbase Commerce Settings page, available here: %s',
'coinbase'
),
esc_url( 'https://commerce.coinbase.com/dashboard/settings' )
),
),
'webhook_secret' => array(
'title' => __( 'Webhook Shared Secret', 'coinbase' ),
'type' => 'text',
'description' =>
// translators: Instructions for setting up 'webhook shared secrets' on settings page.
__( 'Using webhooks allows Coinbase Commerce to send payment confirmation messages to the website. To fill this out:', 'coinbase' )
. '<br /><br />' .
// translators: Step 1 of the instructions for 'webhook shared secrets' on settings page.
__( '1. In your Coinbase Commerce settings page, scroll to the \'Webhook subscriptions\' section', 'coinbase' )
. '<br />' .
// translators: Step 2 of the instructions for 'webhook shared secrets' on settings page. Includes webhook URL.
sprintf( __( '2. Click \'Add an endpoint\' and paste the following URL: %s', 'coinbase' ), add_query_arg( 'wc-api', 'WC_Gateway_Coinbase', home_url( '/', 'https' ) ) )
. '<br />' .
// translators: Step 3 of the instructions for 'webhook shared secrets' on settings page.
__( '3. Make sure to select "Send me all events", to receive all payment updates.', 'coinbase' )
. '<br />' .
// translators: Step 4 of the instructions for 'webhook shared secrets' on settings page.
__( '4. Click "Show shared secret" and paste into the box above.', 'coinbase' ),
),
'show_icons' => array(
'title' => __( 'Show icons', 'coinbase' ),
'type' => 'checkbox',
'label' => __( 'Display currency icons on checkout page.', 'coinbase' ),
'default' => 'yes',
),
'debug' => array(
'title' => __( 'Debug log', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable logging', 'woocommerce' ),
'default' => 'no',
// translators: Description for 'Debug log' section of settings page.
'description' => sprintf( __( 'Log Coinbase API events inside %s', 'coinbase' ), '<code>' . WC_Log_Handler_File::get_log_file_path( 'coinbase' ) . '</code>' ),
),
);
}
/**
* Process the payment and return the result.
*
* @param int $order_id
* @return array
*/
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
// Create description for charge based on order's products. Ex: 1 x Product1, 2 x Product2
try {
$order_items = array_map( function( $item ) {
return $item['quantity'] . ' x ' . $item['name'];
}, $order->get_items() );
$description = mb_substr( implode( ', ', $order_items ), 0, 200 );
} catch ( Exception $e ) {
$description = null;
}
$this->init_api();
// Create a new charge.
$metadata = array(
'order_id' => strval($order->get_id()),
'order_key' => $order->get_order_key(),
'source' => 'woocommerce'
);
$result = Coinbase_API_Handler::create_charge(
$order->get_total(), get_woocommerce_currency(), $metadata,
$this->get_return_url( $order ), null, $description,
$this->get_cancel_url( $order )
);
if ( ! $result[0] ) {
return array( 'result' => 'fail' );
}
$charge = $result[1]['data'];
$order->update_meta_data( '_coinbase_charge_id', $charge['id'] );
$order->save();
return array(
'result' => 'success',
'redirect' => $charge['hosted_url'],
);
}
/**
* Get the cancel url.
*
* @param WC_Order $order Order object.
* @return string
*/
public function get_cancel_url( $order ) {
$return_url = $order->get_cancel_order_url();
if ( is_ssl() || get_option( 'woocommerce_force_ssl_checkout' ) == 'yes' ) {
$return_url = str_replace( 'http:', 'https:', $return_url );
}
/** DOCBLOCK - Makes linter happy.
*
* @since today
*/
return apply_filters( 'woocommerce_get_cancel_url', $return_url, $order );
}
/**
* Check payment statuses on orders and update order statuses.
*/
public function check_orders() {
$this->init_api();
// Check the status of non-archived Coinbase orders.
$orders = wc_get_orders(
array(
'coinbase_archived' => false,
'status' => array( 'wc-pending' ),
'meta_query' => array(
array(
'key' => '_coinbase_archived',
'compare' => 'NOT EXISTS',
),
array(
'key' => '_coinbase_charge_id',
'compare' => 'EXISTS',
)
)
)
);
foreach ( $orders as $order ) {
$charge_id = $order->get_meta( '_coinbase_charge_id' );
usleep( 300000 ); // Ensure we don't hit the rate limit.
$result = Coinbase_API_Handler::send_request( 'charges/' . $charge_id );
if ( ! $result[0] ) {
self::log( 'Failed to fetch order updates for: ' . $order->get_id() );
continue;
}
$timeline = $result[1]['data']['timeline'];
self::log( 'Timeline: ' . print_r( $timeline, true ) );
$this->_update_order_status( $order, $timeline );
}
}
/**
* Handle requests sent to webhook.
*/
public function handle_webhook() {
$payload = file_get_contents( 'php://input' );
if ( ! empty( $payload ) && $this->validate_webhook( $payload ) ) {
$data = json_decode( $payload, true );
$event_data = $data['event']['data'];
self::log( 'Webhook received event: ' . print_r( $data, true ) );
if ( ! isset( $event_data['metadata']['order_id'] ) ) {
// Probably a charge not created by us.
exit;
}
$order_id = $event_data['metadata']['order_id'];
$this->_update_order_status( wc_get_order( $order_id ), $event_data['timeline'] );
exit; // 200 response for acknowledgement.
}
wp_die( 'Coinbase Webhook Request Failure', 'Coinbase Webhook', array( 'response' => 500 ) );
}
/**
* Check Coinbase webhook request is valid.
*
* @param string $payload
*/
public function validate_webhook( $payload ) {
self::log( 'Checking Webhook response is valid' );
if ( ! isset( $_SERVER['HTTP_X_CC_WEBHOOK_SIGNATURE'] ) ) {
return false;
}
$sig = $_SERVER['HTTP_X_CC_WEBHOOK_SIGNATURE'];
$secret = $this->get_option( 'webhook_secret' );
$sig2 = hash_hmac( 'sha256', $payload, $secret );
if ( $sig === $sig2 ) {
return true;
}
return false;
}
/**
* Init the API class and set the API key etc.
*/
protected function init_api() {
include_once dirname( __FILE__ ) . '/includes/class-coinbase-api-handler.php';
Coinbase_API_Handler::$log = get_class( $this ) . '::log';
Coinbase_API_Handler::$api_key = $this->get_option( 'api_key' );
}
/**
* Update the status of an order from a given timeline.
*
* @param WC_Order $order
* @param array $timeline
*/
public function _update_order_status( $order, $timeline ) {
$prev_status = $order->get_meta( '_coinbase_status' );
$last_update = end( $timeline );
$status = $last_update['status'];
if ( $status !== $prev_status ) {
$order->update_meta_data( '_coinbase_status', $status );
if ( 'EXPIRED' === $status && 'pending' == $order->get_status() ) {
$order->update_status( 'cancelled', __( 'Coinbase payment expired.', 'coinbase' ) );
} elseif ( 'CANCELED' === $status ) {
$order->update_status( 'cancelled', __( 'Coinbase payment cancelled.', 'coinbase' ) );
} elseif ( 'PENDING' === $status ) {
$order->update_status( 'blockchainpending', __( 'Coinbase payment detected, but awaiting blockchain confirmation.', 'coinbase' ) );
} elseif ( 'COMPLETED' === $status ) {
$order->update_status( 'processing', __( 'Coinbase payment was successfully processed.', 'coinbase' ) );
$order->payment_complete();
}
}
// Archive if in a resolved state and idle more than timeout.
if ( in_array( $status, array( 'EXPIRED', 'COMPLETED' ), true ) &&
$order->get_date_modified() < $this->timeout ) {
self::log( 'Archiving order: ' . $order->get_order_number() );
$order->update_meta_data( '_coinbase_archived', true );
}
}
/**
* Handle a custom 'coinbase_archived' query var to get orders
* payed through Coinbase with the '_coinbase_archived' meta.
*
* @param array $query - Args for WP_Query.
* @param array $query_vars - Query vars from WC_Order_Query.
* @return array modified $query
*/
public function _custom_query_var( $query, $query_vars ) {
if ( array_key_exists( 'coinbase_archived', $query_vars ) ) {
$query['meta_query'][] = array(
'key' => '_coinbase_archived',
'compare' => $query_vars['coinbase_archived'] ? 'EXISTS' : 'NOT EXISTS',
);
// Limit only to orders payed through Coinbase.
$query['meta_query'][] = array(
'key' => '_coinbase_charge_id',
'compare' => 'EXISTS',
);
}
return $query;
}
}