diff --git a/php/Blockonomics.php b/php/Blockonomics.php
index 087a966e..9088ba0c 100755
--- a/php/Blockonomics.php
+++ b/php/Blockonomics.php
@@ -7,7 +7,6 @@ class Blockonomics
{
const BASE_URL = 'https://www.blockonomics.co';
const STORES_URL = self::BASE_URL . '/api/v2/stores?wallets=true';
- const WALLETS_URL = self::BASE_URL . '/api/v2/wallets';
const NEW_ADDRESS_URL = self::BASE_URL . '/api/new_address';
const PRICE_URL = self::BASE_URL . '/api/price';
@@ -160,16 +159,14 @@ public function getActiveCurrencies() {
}
$callback_url = $this->get_callback_url();
- $match_result = $this->findMatchingStore($stores_result['stores'], $callback_url);
- $matching_store = $match_result['store'];
- $match_type = $match_result['match_type'];
+ $matching_store = $this->findExactMatchingStore($stores_result['stores'], $callback_url);
// Result currencies
$checkout_currencies = [];
$supported_currencies = $this->getSupportedCurrencies();
- // Add currencies from Blockonomics store
- if ($match_type === 'exact') {
+ // Add currencies from Blockonomics store if exact match is found
+ if ($matching_store) {
$blockonomics_enabled = $this->getStoreEnabledCryptos($matching_store);
foreach ($blockonomics_enabled as $code) {
if ($code != 'bch' && isset($supported_currencies[$code])) {
@@ -244,16 +241,6 @@ private function get_stores($api_key) {
return $result;
}
- private function update_store($store_id, $data) {
- // Ensure we're using the specific store endpoint
- $url = self::BASE_URL . '/api/v2/stores/' . $store_id;
- $response = $this->post($url, $this->api_key, wp_json_encode($data), 45);
- if (wp_remote_retrieve_response_code($response) !== 200) {
- return __('Could not update store callback', 'blockonomics-bitcoin-payments');
- }
- return false;
- }
-
private function get($url, $api_key = '')
{
$headers = $this->set_headers($api_key);
@@ -331,126 +318,25 @@ public function saveBlockonomicsEnabledCryptos($cryptos)
}
}
- /**
- * Find a matching store based on callback URL
+ /* Find store with exact callback URL match, if multiple matches exist, prefers store with wallets attached
*
- * @param array $stores List of stores from Blockonomics API
+ * @param array $stores List of stores from API
* @param string $callback_url The callback URL to match
- * @return array [
- * 'store' => object|null,
- * 'match_type' => 'exact'|'partial'|'empty'|'none',
- * 'duplicate_count' => int // Number of duplicate stores found
- * ]
+ * @return object|null Matching store or null
*/
- private function findMatchingStore($stores, $callback_url)
- {
- $exact_matches = [];
- $partial_matches = [];
- $empty_callback_matches = [];
-
+ private function findExactMatchingStore($stores, $callback_url) {
+ $best_store = null;
foreach ($stores as $store) {
- // Exact match
if ($store->http_callback === $callback_url) {
- $exact_matches[] = $store;
- continue;
- }
-
- // Store without callback
- if (empty($store->http_callback)) {
- $empty_callback_matches[] = $store;
- continue;
- }
-
- // Partial match - only secret or protocol differs
- $store_base_url = preg_replace(['/https?:\/\//', '/\?.*$/'], '', $store->http_callback);
- $target_base_url = preg_replace(['/https?:\/\//', '/\?.*$/'], '', $callback_url);
-
- // strip language prefix patterns (/xx/ or /xx-xx/) for WPML/Polylang compatibility
- $store_base_url = preg_replace('#/[a-z]{2}(-[a-z]{2})?/wc-api/#i', '/wc-api/', $store_base_url);
- $target_base_url = preg_replace('#/[a-z]{2}(-[a-z]{2})?/wc-api/#i', '/wc-api/', $target_base_url);
-
- if ($store_base_url === $target_base_url) {
- $partial_matches[] = $store;
- }
- }
-
- // return best available match in this order of preference :=> exact > partial > empty > none
- if (!empty($exact_matches)) {
- $best_store = $this->selectBestStore($exact_matches);
- return [
- 'store' => $best_store,
- 'match_type' => 'exact',
- 'duplicate_count' => count($exact_matches) - 1
- ];
- } elseif (!empty($partial_matches)) {
- $best_store = $this->selectBestStore($partial_matches);
- return [
- 'store' => $best_store,
- 'match_type' => 'partial',
- 'duplicate_count' => count($partial_matches) - 1
- ];
- } elseif (!empty($empty_callback_matches)) {
- $best_store = $this->selectBestStore($empty_callback_matches);
- return [
- 'store' => $best_store,
- 'match_type' => 'empty',
- 'duplicate_count' => count($empty_callback_matches) - 1
- ];
- } else {
- return ['store' => null, 'match_type' => 'none', 'duplicate_count' => 0];
- }
- }
-
- /**
- * Select the best store from a list of candidates
- * @param array $stores List of store objects
- * @return object Best store from the list
- */
- private function selectBestStore($stores)
- {
- if (count($stores) === 1) {
- return $stores[0];
- }
-
- $best_store = $stores[0];
- $best_score = $this->scoreStore($stores[0]);
-
- for ($i = 1; $i < count($stores); $i++) {
- $score = $this->scoreStore($stores[$i]);
- if ($score > $best_score) {
- $best_score = $score;
- $best_store = $stores[$i];
+ // prefer store with wallets (so checkout works)
+ if (!$best_store || (!empty($store->wallets) && empty($best_store->wallets))) {
+ $best_store = $store;
+ }
}
}
-
return $best_store;
}
- /**
- * Score a store for selection priority. This is when user creates multiple store with exact same callback url
- * Scoring:
- * - Has wallets/crypto: +10 (critical for checkout)
- * - Has non-empty name: +1 (tie-breaker for display purposes only, also empty name signifies double click during setup wizard or browser back/forward button pressed quickly)
- * Note: Name is only a tie-breaker. If only one store matches, it's used regardless of whether it has a name. The crypto check is what matters for functionality.
- * @param object $store Store object with wallets and name properties
- * @return int Score value
- */
- private function scoreStore($store)
- {
- $score = 0;
- // Has crypto/wallets enabled: +10 (most imp factor as this leads to checkout working w/o issue)
- if (!empty($store->wallets)) {
- $score += 10;
- }
- // Has a non-empty name: +1 (tie-breaker only, for better display in admin)
- // API returns empty string for nameless stores
- $name = trim($store->name ?? '');
- if (!empty($name)) {
- $score += 1;
- }
- return $score;
- }
-
/**
* Helper to check API response for errors.
*
@@ -480,48 +366,6 @@ private function check_api_response_error($response)
return false;
}
- /**
- * Get the wallets from the API, also checks if API key is valid.
- *
- * @param string $api_key Blockonomics API key.
- * @return array [
- * 'error' => string, // Error message if any
- * 'wallets' => array // Array of configured wallet currencies
- * ]
- */
- public function get_wallets($api_key)
- {
- $response = $this->get(self::WALLETS_URL, $api_key);
-
- $error = $this->check_api_response_error($response);
- if ($error) {
- return ['error' => $error];
- }
-
- $body = wp_remote_retrieve_body($response);
- $response_data = json_decode($body);
-
- if (!$response_data || !isset($response_data->data)) {
- return ['error' => __('Invalid response was received. Please retry.', 'blockonomics-bitcoin-payments')];
- }
-
- $wallets = [];
- foreach ($response_data->data as $wallet) {
- if (!empty($wallet->crypto)) {
- $crypto = strtolower($wallet->crypto);
- if (!in_array($crypto, $wallets)) {
- $wallets[] = $crypto;
- }
- }
- }
-
- if (empty($wallets)) {
- return ['error' => __('Please add a Wallet on Blockonomics Dashboard', 'blockonomics-bitcoin-payments')];
- }
-
- return ['wallets' => $wallets];
- }
-
public function testSetup()
{
// just clear these first, they will only be set again on success
@@ -534,37 +378,16 @@ public function testSetup()
return $this->setup_error(__('API Key is not set. Please enter your API Key.', 'blockonomics-bitcoin-payments'));
}
- $wallet_result = $this->get_wallets($api_key);
- if (!empty($wallet_result['error'])) {
- return $this->setup_error($wallet_result['error']);
- }
-
$stores_result = $this->get_stores($api_key);
if (!empty($stores_result['error'])) {
return $this->setup_error($stores_result['error']);
}
$callback_url = $this->get_callback_url();
- $match_result = $this->findMatchingStore($stores_result['stores'], $callback_url);
- $matching_store = $match_result['store'];
- $match_type = $match_result['match_type'];
-
- if ($match_type === 'none') {
- return $this->setup_error(__('Please add a Store on Blockonomics Dashboard', 'blockonomics-bitcoin-payments'));
- }
-
- if ($match_type === 'partial') {
- return $this->setup_error(__('Please copy Callback URL from Advanced Settings and paste it as your Store Callback URL', 'blockonomics-bitcoin-payments'));
- }
+ $matching_store = $this->findExactMatchingStore($stores_result['stores'], $callback_url);
- if ($match_type === 'empty') {
- $update_result = $this->update_store($matching_store->id, [
- 'name' => $matching_store->name,
- 'http_callback' => $callback_url
- ]);
- if (!empty($update_result)) {
- return $this->setup_error($update_result);
- }
+ if (!$matching_store) {
+ return $this->setup_error(__('Please add a new store with the callback URL shown in advanced settings', 'blockonomics-bitcoin-payments'));
}
$this->update_store_name_option($matching_store->name);
diff --git a/php/form_fields.php b/php/form_fields.php
index a6f8a3cd..99408748 100755
--- a/php/form_fields.php
+++ b/php/form_fields.php
@@ -39,7 +39,7 @@ public static function init_form_fields($callback_url = '') {
'subtitle' => __('Title', 'blockonomics-bitcoin-payments'),
'type' => 'text',
'description' => __('Payment method for bitcoin displayed to the user during checkout.', 'blockonomics-bitcoin-payments'),
- 'default' => __('Crypto', 'blockonomics-bitcoin-payments'),
+ 'default' => __('Pay with Crypto', 'blockonomics-bitcoin-payments'),
'placeholder' => __('Title', 'blockonomics-bitcoin-payments')
),
'description' => array(