Changeset 3458758
- Timestamp:
- 02/11/2026 08:20:41 AM (8 weeks ago)
- Location:
- coinsnap-bitcoin-invoice-form
- Files:
-
- 52 added
- 13 edited
-
tags/1.0.2 (added)
-
tags/1.0.2/assets (added)
-
tags/1.0.2/assets/css (added)
-
tags/1.0.2/assets/css/admin.css (added)
-
tags/1.0.2/assets/css/frontend.css (added)
-
tags/1.0.2/assets/css/index.php (added)
-
tags/1.0.2/assets/index.php (added)
-
tags/1.0.2/assets/js (added)
-
tags/1.0.2/assets/js/admin.js (added)
-
tags/1.0.2/assets/js/frontend.js (added)
-
tags/1.0.2/assets/js/index.php (added)
-
tags/1.0.2/coinsnap-bitcoin-invoice-form.php (added)
-
tags/1.0.2/index.php (added)
-
tags/1.0.2/languages (added)
-
tags/1.0.2/languages/index.php (added)
-
tags/1.0.2/readme.txt (added)
-
tags/1.0.2/src (added)
-
tags/1.0.2/src/Admin (added)
-
tags/1.0.2/src/Admin/class-coinsnapbif-admin-logs-page.php (added)
-
tags/1.0.2/src/Admin/class-coinsnapbif-admin-settings.php (added)
-
tags/1.0.2/src/Admin/class-coinsnapbif-admin-transactions-page.php (added)
-
tags/1.0.2/src/Admin/index.php (added)
-
tags/1.0.2/src/CPT (added)
-
tags/1.0.2/src/CPT/class-coinsnapbif-cpt-invoice-form-post-type.php (added)
-
tags/1.0.2/src/CPT/index.php (added)
-
tags/1.0.2/src/Database (added)
-
tags/1.0.2/src/Database/class-installer.php (added)
-
tags/1.0.2/src/Database/index.php (added)
-
tags/1.0.2/src/Providers (added)
-
tags/1.0.2/src/Providers/Payment (added)
-
tags/1.0.2/src/Providers/Payment/class-btcpayprovider.php (added)
-
tags/1.0.2/src/Providers/Payment/class-coinsnapprovider.php (added)
-
tags/1.0.2/src/Providers/Payment/class-paymentproviderinterface.php (added)
-
tags/1.0.2/src/Providers/Payment/index.php (added)
-
tags/1.0.2/src/Providers/index.php (added)
-
tags/1.0.2/src/Rest (added)
-
tags/1.0.2/src/Rest/class-coinsnapbif-rest-routes.php (added)
-
tags/1.0.2/src/Rest/index.php (added)
-
tags/1.0.2/src/Services (added)
-
tags/1.0.2/src/Services/class-coinsnapbif-services-payment-service.php (added)
-
tags/1.0.2/src/Services/index.php (added)
-
tags/1.0.2/src/Shortcode (added)
-
tags/1.0.2/src/Shortcode/class-coinsnapbif-shortcode-invoice-form-shortcode.php (added)
-
tags/1.0.2/src/Shortcode/index.php (added)
-
tags/1.0.2/src/Util (added)
-
tags/1.0.2/src/Util/class-coinsnapbif-log-levels.php (added)
-
tags/1.0.2/src/Util/class-coinsnapbif-logger.php (added)
-
tags/1.0.2/src/Util/class-coinsnapbif-util-provider-factory.php (added)
-
tags/1.0.2/src/Util/index.php (added)
-
tags/1.0.2/src/class-coinsnapbif-constants.php (added)
-
tags/1.0.2/src/class-coinsnapbif-plugin.php (added)
-
tags/1.0.2/src/index.php (added)
-
trunk/assets/css/admin.css (modified) (1 diff)
-
trunk/assets/js/admin.js (modified) (1 diff)
-
trunk/coinsnap-bitcoin-invoice-form.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/src/Admin/class-coinsnapbif-admin-settings.php (modified) (3 diffs)
-
trunk/src/Admin/class-coinsnapbif-admin-transactions-page.php (modified) (1 diff)
-
trunk/src/Providers/Payment/class-btcpayprovider.php (modified) (1 diff)
-
trunk/src/Providers/Payment/class-coinsnapprovider.php (modified) (1 diff)
-
trunk/src/Providers/Payment/class-paymentproviderinterface.php (modified) (1 diff)
-
trunk/src/Services/class-coinsnapbif-services-payment-service.php (modified) (2 diffs)
-
trunk/src/Util/class-coinsnapbif-util-provider-factory.php (modified) (1 diff)
-
trunk/src/class-coinsnapbif-constants.php (modified) (2 diffs)
-
trunk/src/class-coinsnapbif-plugin.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
coinsnap-bitcoin-invoice-form/trunk/assets/css/admin.css
r3439284 r3458758 2 2 * Bitcoin Invoice Form - Admin Styles 3 3 */ 4 5 .coinsnapConnectionStatus{ 6 font-size:1.3em; 7 font-weight: 600; 8 margin-top:1em; 9 margin-bottom:1em; 10 } 11 12 .coinsnapConnectionStatus span:before { 13 content:""; 14 border-radius: 50%; 15 display:inline-block; 16 vertical-align: baseline; 17 width:10px; height:10px; 18 margin:0 5px 0 0; 19 } 20 21 .coinsnapConnectionStatus span.error { 22 color: #d63638; 23 } 24 25 .coinsnapConnectionStatus span.error:before { 26 background:#d63638; 27 } 28 29 .coinsnapConnectionStatus span.success { 30 color: #00a32a; 31 } 32 33 .coinsnapConnectionStatus span.success:before { 34 background:#00a32a; 35 } 36 37 .button.btcpay-apikey-link {margin:10px 0;} 4 38 5 39 /* General Admin Styles - matching wp-bitcoin-newsletter */ -
coinsnap-bitcoin-invoice-form/trunk/assets/js/admin.js
r3439284 r3458758 49 49 // Initialize other admin features 50 50 initAdminFeatures(); 51 52 53 54 $('#coinsnapbif_btcpay_wizard_button').click(function(e) { 55 e.preventDefault(); 56 const host = $('#btcpay_url').val(); 57 if (isCoinsnapBIFValidUrl(host)) { 58 let data = { 59 'action': 'coinsnapbif_btcpay_apiurl_handler', 60 'host': host, 61 'apiNonce': coinsnapbif_ajax.nonce 62 }; 63 64 $.post(coinsnapbif_ajax.ajax_url, data, function(response) { 65 if (response.data.url) { 66 window.location = response.data.url; 67 } 68 }).fail( function() { 69 alert('Error processing your request. Please make sure to enter a valid BTCPay Server instance URL.') 70 }); 71 } 72 else { 73 alert('Please enter a valid url including https:// in the BTCPay Server URL input field.') 74 } 51 75 }); 76 77 if($('#coinsnap_bitcoin_invoice_polls_currency').length){ 78 79 setStep(); 80 $('#coinsnap_bitcoin_invoice_polls_currency').change( 81 function(){ 82 setStep(); 83 } 84 ); 85 86 } 87 88 /* 89 if($('.coinsnapConnectionStatus').length){ 90 91 console.log('Connection check is activated'); 92 93 let ajaxurl = coinsnapbif_ajax.ajax_url; 94 let data = { 95 action: 'coinsnapbif_connection_handler', 96 apiNonce: coinsnapbif_ajax.nonce, 97 apiPost: coinsnapbif_ajax.post 98 }; 99 100 jQuery.post( ajaxurl, data, function( response ){ 101 102 var connectionCheckResponse = $.parseJSON(response); 103 let resultClass = (connectionCheckResponse.result === true)? 'success' : 'error'; 104 $('.coinsnapConnectionStatus').html('<span class="'+resultClass+'">'+ connectionCheckResponse.message +'</span>'); 105 106 }); 107 } 108 */ 109 }); 110 111 function setStep(){ 112 let step = 0.01; 113 let currency = $('#coinsnap_bitcoin_invoice_polls_currency').val(); 114 if(currency === 'RUB' || currency === 'JPY' || currency === 'SATS'){ 115 step = 1; 116 } 117 $('#coinsnap_bitcoin_invoice_polls_amount').attr('step', step); 118 } 119 120 function isCoinsnapBIFValidUrl(serverUrl) { 121 if(serverUrl.indexOf('http') > -1){ 122 try { 123 const url = new URL(serverUrl); 124 if (url.protocol !== 'https:' && url.protocol !== 'http:') { 125 return false; 126 } 127 } 128 catch (e) { 129 console.error(e); 130 return false; 131 } 132 return true; 133 } 134 else { 135 return false; 136 } 137 } 52 138 53 139 /** -
coinsnap-bitcoin-invoice-form/trunk/coinsnap-bitcoin-invoice-form.php
r3445785 r3458758 4 4 * Plugin URI: https://coinsnap.io/modules/bitcoin-invoice/ 5 5 * Description: Generate and embed customizable Bitcoin Invoice Forms on your website. Customers can complete and pay invoices directly on your site with payment processing via Coinsnap or BTCPay Server. 6 * Version: 1.0. 16 * Version: 1.0.2 7 7 * Author: Coinsnap 8 8 * Author URI: https://coinsnap.io/ … … 25 25 26 26 if(!defined('COINSNAPBIF_REFERRAL_CODE' ) ) { define( 'COINSNAPBIF_REFERRAL_CODE', 'D85536' );} 27 if(!defined('COINSNAPBIF_VERSION' ) ) { define( 'COINSNAPBIF_VERSION', '1.0. 1' );}27 if(!defined('COINSNAPBIF_VERSION' ) ) { define( 'COINSNAPBIF_VERSION', '1.0.2' );} 28 28 if(!defined('COINSNAPBIF_PHP_VERSION' ) ) { define( 'COINSNAPBIF_PHP_VERSION', '7.4' );} 29 29 if(!defined('COINSNAP_CURRENCIES')){define( 'COINSNAP_CURRENCIES', array("EUR","USD","SATS","BTC","CAD","JPY","GBP","CHF","RUB") );} -
coinsnap-bitcoin-invoice-form/trunk/readme.txt
r3445785 r3458758 4 4 Tags: Lightning, bitcoin, invoice form, BTCPay 5 5 Tested up to: 6.9 6 Stable tag: 1.0. 16 Stable tag: 1.0.2 7 7 License: GPL2 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 235 235 * Updated plugin URI. 236 236 * Updated default field labels for invoice form. 237 238 = 1.0.2 :: 2026-02-11 = 239 * Update: added Coinsnap and BTCPay server connection check in admin. 240 * Update: added webhook check and registration functionality. 241 * Fixed: payment provider override functionality for a specific form. -
coinsnap-bitcoin-invoice-form/trunk/src/Admin/class-coinsnapbif-admin-settings.php
r3439284 r3458758 19 19 class CoinsnapBIF_Admin_Settings { 20 20 public const OPTION_KEY = 'bif_settings'; 21 public const WEBHOOK_KEY = 'coinsnapbif_webhook'; 21 22 22 23 /** Register hooks to initialize settings. */ … … 24 25 add_action( 'admin_init', array( __CLASS__, 'register_settings' ) ); 25 26 } 26 27 /**27 28 /** 28 29 * Get merged settings with defaults. 29 30 * … … 257 258 echo '<form method="post" action="options.php">'; 258 259 settings_fields( 'coinsnapbif_settings_group' ); 260 261 echo '<div class="coinsnapConnectionStatus"></div>'; 259 262 260 263 // Render general settings section -
coinsnap-bitcoin-invoice-form/trunk/src/Admin/class-coinsnapbif-admin-transactions-page.php
r3439284 r3458758 36 36 37 37 $table_name = Installer::table_name(); 38 $per_page = 5;38 $per_page = 10; 39 39 $_paged = filter_input(INPUT_GET,'paged',FILTER_SANITIZE_FULL_SPECIAL_CHARS); 40 40 $_nonce = filter_input(INPUT_GET,'_wpnonce',FILTER_SANITIZE_FULL_SPECIAL_CHARS); -
coinsnap-bitcoin-invoice-form/trunk/src/Providers/Payment/class-btcpayprovider.php
r3439284 r3458758 21 21 */ 22 22 class BTCPayProvider implements PaymentProviderInterface { 23 /** 23 24 /** 25 * Get store data from BTCPay server 26 * 27 * @param void. 28 * @return array(). 29 */ 30 public function get_store(): array { 31 // BTCPay server connection credentials check 32 33 $s = Settings::get_settings(); 34 $host = rtrim( (string) $s['btcpay_host'], '/' ); 35 $api_key = (string) $s['btcpay_api_key']; 36 $store = (string) $s['btcpay_store_id']; 37 38 if ( ! $host || ! $api_key || ! $store ) { 39 return array('error' => true,'message'=>__('Connection credentials error','coinsnap-bitcoin-invoice-form')); 40 } 41 42 $url = $host . sprintf( CoinsnapBIF_Constants::BTCPAY_STORE_ENDPOINT, rawurlencode( $store ) ); 43 44 $args = array( 45 'method' => 'GET', 46 'headers' => array( 47 'Authorization' => 'token ' . $api_key, 48 'Content-Type' => 'application/json', 49 ), 50 'timeout' => 20 51 ); 52 53 $res = wp_remote_request( $url, $args ); 54 55 if ( is_wp_error( $res ) ) { 56 return array('error' => true,'message'=>__('Store data error','coinsnap-bitcoin-invoice-form')); 57 } 58 59 $code = wp_remote_retrieve_response_code( $res ); 60 $result = json_decode( wp_remote_retrieve_body( $res ), true ); 61 if ( $code >= 200 && $code < 300 && is_array($result) ) { 62 return ['code' => $code, 'result' => $result]; 63 } 64 else { 65 return array('error' => true,'message'=>__('BTCPay server request error','coinsnap-bitcoin-invoice-form')); 66 } 67 } 68 69 70 /** 71 * Check existing webhook on BTCPay server. 72 * 73 * @param void. 74 * @return bool. 75 */ 76 public function check_webhook(): bool { 77 78 $webhookExists = false; 79 $s = Settings::get_settings(); 80 81 // BTCPay server connection credentials check 82 83 $host = rtrim( (string) $s['btcpay_host'], '/' ); 84 $api_key = (string) $s['btcpay_api_key']; 85 $store = (string) $s['btcpay_store_id']; 86 $webhook_url = rtrim( (string) get_home_url(), '/' ) . '/wp-json/' . CoinsnapBIF_Constants::REST_NAMESPACE . CoinsnapBIF_Constants::REST_ROUTE_WEBHOOK_BTCPAY; 87 88 if ( ! $host || ! $api_key || ! $store ) { 89 return false; 90 } 91 92 if ($storedWebhook = get_option(Settings::WEBHOOK_KEY)['btcpay']) { 93 94 $url = $host . sprintf( CoinsnapBIF_Constants::BTCPAY_WEBHOOKS_ENDPOINT, rawurlencode( $store ) ); 95 96 $args = array( 97 'method' => 'GET', 98 'headers' => array( 99 'Authorization' => 'token ' . $api_key, 100 'Content-Type' => 'application/json', 101 ), 102 'timeout' => 20, 103 ); 104 105 $res = wp_remote_request( $url, $args ); 106 107 if ( is_wp_error( $res ) ) { 108 return false; 109 } 110 111 $code = wp_remote_retrieve_response_code( $res ); 112 $storeWebhooks = json_decode( wp_remote_retrieve_body( $res ), true ); 113 if ( $code >= 200 && $code < 300 && is_array($storeWebhooks) ) { 114 115 // Registered webhooks analysis 116 foreach($storeWebhooks as $webhook){ 117 118 // If webhook is registered this site 119 if(strpos( $webhook['url'], $webhook_url ) !== false){ 120 121 // Return TRUE if stored webhook ID equals registered webhook ID 122 if($webhook['id'] === $storedWebhook['id']){ 123 $webhookExists = true; 124 } 125 126 // If not - we delete this webhook from server 127 else { 128 129 $url = $host . sprintf( CoinsnapBIF_Constants::BTCPAY_WEBHOOKS_ENDPOINT, rawurlencode( $store ) ) . '/' . $webhook['id']; 130 $args = array( 131 'method' => 'DELETE', 132 'headers' => array( 133 'Authorization' => 'token ' . $api_key, 134 'Content-Type' => 'application/json', 135 ), 136 'timeout' => 20, 137 ); 138 $res = wp_remote_request( $url, $args ); 139 $code = wp_remote_retrieve_response_code( $res ); 140 if ($code !== 204 && $code !== 200) { 141 142 } 143 } 144 } 145 } 146 147 return $webhookExists; 148 } 149 return false; 150 } 151 else { 152 return false; 153 } 154 } 155 156 /** 157 * Webhook registration on BTCPay Server. 158 * 159 * @param void. 160 * @return array { id: string, secret: string, url: string } 161 */ 162 public function register_webhook(): array { 163 164 // BTCPay server connection credentials check 165 166 $s = Settings::get_settings(); 167 $host = rtrim( (string) $s['btcpay_host'], '/' ); 168 $api_key = (string) $s['btcpay_api_key']; 169 $store = (string) $s['btcpay_store_id']; 170 $webhook_url = rtrim( (string) get_home_url(), '/' ) . '/wp-json/' . CoinsnapBIF_Constants::REST_NAMESPACE . CoinsnapBIF_Constants::REST_ROUTE_WEBHOOK_BTCPAY; 171 172 if ( ! $host || ! $api_key || ! $store ) { 173 return array('error' => true,'message'=>__('Connection credentials error','coinsnap-bitcoin-invoice-form')); 174 } 175 176 $data = [ 177 'url' => $webhook_url, 178 'authorizedEvents' => ['everything' => false,'specificEvents' => ['InvoiceCreated','InvoiceExpired','InvoiceSettled','InvoiceProcessing']], 179 ]; 180 181 $url = $host . sprintf( CoinsnapBIF_Constants::BTCPAY_WEBHOOKS_ENDPOINT, rawurlencode( $store ) ); 182 183 $args = array( 184 'method' => 'POST', 185 'headers' => array( 186 'Authorization' => 'token ' . $api_key, 187 'Content-Type' => 'application/json', 188 ), 189 'timeout' => 20, 190 'body' => wp_json_encode($data) 191 ); 192 193 $res = wp_remote_request( $url, $args ); 194 195 if ( is_wp_error( $res ) ) { 196 return array('error' => true,'message'=>__('Webhook creation error','coinsnap-bitcoin-invoice-form')); 197 } 198 199 $code = wp_remote_retrieve_response_code( $res ); 200 $result = json_decode( wp_remote_retrieve_body( $res ), true ); 201 if ( $code >= 200 && $code < 300 && is_array($result) ) { 202 return ['code' => $code, 'result' => $result]; 203 } 204 else { 205 return array('error' => true,'message'=>__('BTCPay server request error','coinsnap-bitcoin-invoice-form'),'code' => $code, 'result' => $result); 206 } 207 208 } 209 210 /** 24 211 * Create a payment invoice. 25 212 * -
coinsnap-bitcoin-invoice-form/trunk/src/Providers/Payment/class-coinsnapprovider.php
r3445785 r3458758 22 22 */ 23 23 class CoinsnapProvider implements PaymentProviderInterface { 24 /** 24 25 /** 26 * Get store data from Coinsnap server 27 * 28 * @param void. 29 * @return array(). 30 */ 31 public function get_store(): array { 32 // Coinsnap server connection credentials check 33 34 $settings = Settings::get_settings(); 35 $api_base = rtrim( $settings['coinsnap_api_base'] ? $settings['coinsnap_api_base'] : CoinsnapBIF_Constants::COINSNAP_DEFAULT_API_BASE, '/' ); 36 $api_key = (string) $settings['coinsnap_api_key']; 37 $store = (string) $settings['coinsnap_store_id']; 38 39 40 if ( ! $api_base || ! $api_key || ! $store ) { 41 return array('error' => true,'message'=>__('Connection credentials error','coinsnap-bitcoin-invoice-form')); 42 } 43 44 $url = $api_base . sprintf( CoinsnapBIF_Constants::COINSNAP_STORE_ENDPOINT_V1, rawurlencode( $store ) ); 45 46 $args = array( 47 'method' => 'GET', 48 'headers' => array( 49 'X-Api-Key' => $api_key, 50 'Authorization' => 'token ' . $api_key, 51 'Content-Type' => 'application/json', 52 'accept' => 'application/json', 53 ), 54 'timeout' => 20 55 ); 56 57 $res = wp_remote_request( $url, $args ); 58 59 if ( is_wp_error( $res ) ) { 60 return array('error' => true,'message'=>__('Store data error','coinsnap-bitcoin-invoice-form')); 61 } 62 63 $code = wp_remote_retrieve_response_code( $res ); 64 $result = json_decode( wp_remote_retrieve_body( $res ), true ); 65 if ( $code >= 200 && $code < 300 && is_array($result) ) { 66 return ['code' => $code, 'result' => $result]; 67 } 68 else { 69 return array('error' => true,'message'=>__('Coinsnap server request error','coinsnap-bitcoin-invoice-form')); 70 } 71 } 72 73 74 /** 75 * Check existing webhook on Coinsnap server. 76 * 77 * @param void. 78 * @return bool. 79 */ 80 public function check_webhook(): bool { 81 82 $webhookExists = false; 83 $settings = Settings::get_settings(); 84 85 // Coinsnap server connection credentials check 86 87 $api_base = rtrim( $settings['coinsnap_api_base'] ? $settings['coinsnap_api_base'] : CoinsnapBIF_Constants::COINSNAP_DEFAULT_API_BASE, '/' ); 88 $api_key = (string) $settings['coinsnap_api_key']; 89 $store = (string) $settings['coinsnap_store_id']; 90 $webhook_url = $api_base . sprintf( CoinsnapBIF_Constants::COINSNAP_WEBHOOKS_ENDPOINT_V1, rawurlencode( $store ) ) . '/' . $webhook['id']; 91 92 if ( ! $api_base || ! $api_key || ! $store ) { 93 return false; 94 } 95 96 if ($storedWebhook = get_option(Settings::WEBHOOK_KEY)['coinsnap']) { 97 98 99 100 $url = $api_base . sprintf( CoinsnapBIF_Constants::COINSNAP_WEBHOOKS_ENDPOINT_V1, rawurlencode( $store ) ); 101 102 $args = array( 103 'method' => 'GET', 104 'headers' => array( 105 'X-Api-Key' => $api_key, 106 'Authorization' => 'token ' . $api_key, 107 'Content-Type' => 'application/json', 108 'accept' => 'application/json', 109 ), 110 'timeout' => 20, 111 ); 112 113 $res = wp_remote_request( $url, $args ); 114 115 if ( is_wp_error( $res ) ) { 116 return false; 117 } 118 119 $code = wp_remote_retrieve_response_code( $res ); 120 $storeWebhooks = json_decode( wp_remote_retrieve_body( $res ), true ); 121 if ( $code >= 200 && $code < 300 && is_array($storeWebhooks) ) { 122 123 // Registered webhooks analysis 124 foreach($storeWebhooks as $webhook){ 125 126 // If webhook is registered this site 127 if(strpos( $webhook['url'], $webhook_url ) !== false){ 128 129 // Return TRUE if stored webhook ID equals registered webhook ID 130 if($webhook['id'] === $storedWebhook['id']){ 131 $webhookExists = true; 132 } 133 134 // If not - we delete this webhook from server 135 else { 136 137 $url = $webhook_url; 138 $args = array( 139 'method' => 'DELETE', 140 'headers' => array( 141 'X-Api-Key' => $api_key, 142 'Authorization' => 'token ' . $api_key, 143 'Content-Type' => 'application/json', 144 'accept' => 'application/json', 145 ), 146 'timeout' => 20, 147 ); 148 $res = wp_remote_request( $url, $args ); 149 $code = wp_remote_retrieve_response_code( $res ); 150 if ($code !== 204 && $code !== 200) { 151 152 } 153 } 154 } 155 } 156 157 return $webhookExists; 158 } 159 return false; 160 } 161 else { 162 return false; 163 } 164 } 165 166 /** 167 * Webhook registration on Coinsnap Server. 168 * 169 * @param void. 170 * @return array { id: string, secret: string, url: string } 171 */ 172 public function register_webhook(): array { 173 174 // Coinsnap server connection credentials check 175 176 $settings = Settings::get_settings(); 177 $api_base = rtrim( $settings['coinsnap_api_base'] ? $settings['coinsnap_api_base'] : CoinsnapBIF_Constants::COINSNAP_DEFAULT_API_BASE, '/' ); 178 $api_key = (string) $settings['coinsnap_api_key']; 179 $store = (string) $settings['coinsnap_store_id']; 180 $webhook_url = $api_base . sprintf( CoinsnapBIF_Constants::COINSNAP_WEBHOOKS_ENDPOINT_V1, rawurlencode( $store ) ) . '/' . $webhook['id']; 181 182 if ( ! $api_base || ! $api_key || ! $store ) { 183 return array('error' => true,'message'=>__('Connection credentials error','coinsnap-bitcoin-invoice-form')); 184 } 185 186 $data = [ 187 'url' => $webhook_url, 188 'authorizedEvents' => ['everything' => false,'specificEvents' => ['New','Expired','Settled','Processing']], 189 ]; 190 191 $url = $api_base . sprintf( CoinsnapBIF_Constants::COINSNAP_WEBHOOKS_ENDPOINT_V1, rawurlencode( $store ) ); 192 193 $args = array( 194 'method' => 'POST', 195 'headers' => array( 196 'X-Api-Key' => $api_key, 197 'Authorization' => 'token ' . $api_key, 198 'Content-Type' => 'application/json', 199 'accept' => 'application/json', 200 ), 201 'timeout' => 20, 202 'body' => wp_json_encode($data) 203 ); 204 205 $res = wp_remote_request( $url, $args ); 206 207 if ( is_wp_error( $res ) ) { 208 return array('error' => true,'message'=>__('Webhook creation error','coinsnap-bitcoin-invoice-form')); 209 } 210 211 $code = wp_remote_retrieve_response_code( $res ); 212 $result = json_decode( wp_remote_retrieve_body( $res ), true ); 213 if ( $code >= 200 && $code < 300 && is_array($result) ) { 214 return ['code' => $code, 'result' => $result]; 215 } 216 else { 217 return array('error' => true,'message'=>__('Coinsnap server request error','coinsnap-bitcoin-invoice-form'),'code' => $code, 'result' => $result); 218 } 219 220 } 221 222 223 /** 25 224 * Create a payment invoice. 26 225 * -
coinsnap-bitcoin-invoice-form/trunk/src/Providers/Payment/class-paymentproviderinterface.php
r3439284 r3458758 40 40 */ 41 41 public function check_invoice_status( string $invoice_id ): array; 42 43 /** 44 * Check webhook. 45 * 46 * @return bool 47 */ 48 public function check_webhook(): bool; 49 50 /** 51 * Webhook registration. 52 * 53 * @return array 54 */ 55 public function register_webhook(): array; 56 57 /** 58 * Getting Store data. 59 * 60 * @return array 61 */ 62 public function get_store(): array; 42 63 } -
coinsnap-bitcoin-invoice-form/trunk/src/Services/class-coinsnapbif-services-payment-service.php
r3445785 r3458758 13 13 use CoinsnapBIF\Util\CoinsnapBIF_Logger; 14 14 use CoinsnapBIF\Util\CoinsnapBIF_Util_Provider_Factory; 15 use CoinsnapBIF\Admin\CoinsnapBIF_Admin_Settings ;15 use CoinsnapBIF\Admin\CoinsnapBIF_Admin_Settings as Settings; 16 16 17 17 if ( ! defined( 'ABSPATH' ) ) { … … 226 226 'currency' => $currency, 227 227 'description' => $invoice_data['description'], 228 'payment_provider' => $payment_config['provider_override'] ?? CoinsnapBIF_Admin_Settings::get_settings()['payment_provider'],228 'payment_provider' => (!empty($payment_config['provider_override']))? $payment_config['provider_override'] : Settings::get_settings()['payment_provider'], 229 229 'payment_invoice_id' => $payment_result['invoice_id'], 230 230 'payment_url' => $payment_result['payment_url'] ?? '', -
coinsnap-bitcoin-invoice-form/trunk/src/Util/class-coinsnapbif-util-provider-factory.php
r3439284 r3458758 29 29 * @return PaymentProviderInterface Provider instance. 30 30 */ 31 public static function payment_for_form( $form_id ): PaymentProviderInterface {31 public static function payment_for_form( $form_id = 0 ): PaymentProviderInterface { 32 32 // Ensure we always work with an integer ID. 33 33 $form_id = (int) $form_id; 34 34 35 35 $settings = Settings::get_settings(); 36 $payment = get_post_meta( $form_id, '_bif_payment', true ); 37 $override = is_array( $payment ) && ! empty( $payment['provider_override'] ) ? $payment['provider_override'] : ''; 38 $key = $override ? $override : $settings['payment_provider']; 36 37 if($form_id > 0){ 38 $payment = get_post_meta( $form_id, '_coinsnapbif_payment', true ); 39 $override = (is_array( $payment ) && ! empty( $payment['provider_override'] )) ? $payment['provider_override'] : ''; 40 } 41 42 $key = (isset($override) && !empty($override)) ? $override : $settings['payment_provider']; 39 43 switch ( $key ) { 40 44 case 'btcpay': -
coinsnap-bitcoin-invoice-form/trunk/src/class-coinsnapbif-constants.php
r3439284 r3458758 24 24 /** CoinSnap endpoints (relative to API base). */ 25 25 public const COINSNAP_DEFAULT_API_BASE = 'https://app.coinsnap.io'; 26 public const COINSNAP_STORE_ENDPOINT_V1 = '/api/v1/stores/%s'; 26 27 public const COINSNAP_INVOICES_ENDPOINT_V1 = '/api/v1/stores/%s/invoices'; 27 28 public const COINSNAP_INVOICES_ENDPOINT_ALT = '/api/stores/%s/invoices'; 29 public const COINSNAP_WEBHOOKS_ENDPOINT_V1 = '/api/v1/stores/%s/webhooks'; 28 30 29 31 /** CoinSnap API header names. */ … … 31 33 32 34 /** BTCPay endpoint (relative to host). */ 33 public const BTCPAY_INVOICES_ENDPOINT = '/api/v1/stores/%s/invoices'; 35 public const BTCPAY_STORE_ENDPOINT = '/api/v1/stores/%s'; 36 public const BTCPAY_INVOICES_ENDPOINT = '/api/v1/stores/%s/invoices'; 37 public const BTCPAY_WEBHOOKS_ENDPOINT = '/api/v1/stores/%s/webhooks'; 34 38 35 39 /** DB table suffixes. */ -
coinsnap-bitcoin-invoice-form/trunk/src/class-coinsnapbif-plugin.php
r3439284 r3458758 16 16 use CoinsnapBIF\Admin\CoinsnapBIF_Admin_Logs_Page as LogsPage; 17 17 use CoinsnapBIF\Rest\CoinsnapBIF_Rest_Routes as RestRoutes; 18 use CoinsnapBIF\Util\CoinsnapBIF_Util_Provider_Factory; 18 19 use CoinsnapBIF\Util\CoinsnapBIF_Logger; 19 20 use CoinsnapBIF\CoinsnapBIF_Constants; … … 27 28 */ 28 29 class CoinsnapBIF_Plugin { 29 /** 30 * Singleton instance. 31 * 32 * @var CoinsnapBIF_Plugin|null 33 */ 34 private static $instance; 35 36 /** 37 * Get singleton instance. 38 * 39 * @return CoinsnapBIF_Plugin 40 */ 41 public static function instance(): CoinsnapBIF_Plugin { 42 if ( ! self::$instance ) { 43 self::$instance = new self(); 44 } 45 return self::$instance; 46 } 47 48 /** 49 * Register hooks on load. 50 */ 51 public function boot(): void { 52 // Initialize logger first. 53 CoinsnapBIF_Logger::init(); 54 55 add_action( 'init', array( InvoiceFormPostType::class, 'register' ) ); 56 add_action( 'init', array( InvoiceFormShortcode::class, 'register' ) ); 57 58 add_action( 'admin_menu', array( $this, 'register_admin_menu' ) ); 59 AdminSettings::register(); 60 TransactionsPage::register(); 61 LogsPage::register(); 62 add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) ); 63 64 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend' ) ); 65 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin' ) ); 66 } 67 68 /** 69 * Register admin menus and submenus. 70 */ 71 public function register_admin_menu(): void { 30 /** 31 * Singleton instance. 32 * 33 * @var CoinsnapBIF_Plugin|null 34 */ 35 private static $instance; 36 37 /** 38 * Get singleton instance. 39 * 40 * @return CoinsnapBIF_Plugin 41 */ 42 public static function instance(): CoinsnapBIF_Plugin { 43 if ( ! self::$instance ) { 44 self::$instance = new self(); 45 } 46 return self::$instance; 47 } 48 49 /** 50 * Register hooks on load. 51 */ 52 public function boot(): void { 53 // Initialize logger first. 54 CoinsnapBIF_Logger::init(); 55 56 add_action( 'init', array( InvoiceFormPostType::class, 'register' ) ); 57 add_action( 'init', array( InvoiceFormShortcode::class, 'register' ) ); 58 59 if (is_admin()) { 60 add_action( 'admin_menu', array( $this, 'register_admin_menu' ) ); 61 add_action('admin_notices', array($this, 'coinsnapbif_notice')); 62 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin' ) ); 63 add_action('wp_ajax_coinsnapbif_btcpay_apiurl_handler', [$this, 'btcpayApiUrlHandler']); 64 add_action('wp_ajax_coinsnapbif_connection_handler', [$this, 'coinsnapConnectionHandler']); 65 } 66 67 AdminSettings::register(); 68 TransactionsPage::register(); 69 LogsPage::register(); 70 add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) ); 71 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend' ) ); 72 73 } 74 75 public function coinsnapbif_notice(string $hook){ 76 77 $post_id = (filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ))? filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : 0; 78 $post_type = (filter_input(INPUT_GET,'post_type',FILTER_SANITIZE_FULL_SPECIAL_CHARS ))? filter_input(INPUT_GET,'post_type',FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : 79 ((!empty($post_id))? get_post_type($post_id) : ''); 80 $page = (filter_input(INPUT_GET,'page',FILTER_SANITIZE_FULL_SPECIAL_CHARS ))? filter_input(INPUT_GET,'page',FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : ''; 81 82 if(stripos($page,'coinsnapbif') !== false || stripos($post_type,'coinsnapbif') !== false){ 83 84 $coinsnap_url = $this->getApiUrl(); 85 $coinsnap_api_key = $this->getApiKey(); 86 $coinsnap_store_id = $this->getStoreId(); 87 $coinsnap_provider = ($this->getPaymentProvider() === 'btcpay')? 'BTCPay server' : 'Coinsnap'; 88 89 if(!isset($coinsnap_url) || empty($coinsnap_url)){ 90 echo '<div class="notice notice-error"><p>'; 91 esc_html_e('Bitcoin Invoice Form: Server URL is not set', 'coinsnap-bitcoin-invoice-form'); 92 echo '</p></div>'; 93 } 94 95 if(!isset($coinsnap_store_id) || empty($coinsnap_store_id)){ 96 echo '<div class="notice notice-error"><p>'; 97 esc_html_e('Bitcoin Invoice Form: Store ID is not set', 'coinsnap-bitcoin-invoice-form'); 98 echo '</p></div>'; 99 } 100 101 if(!isset($coinsnap_api_key) || empty($coinsnap_api_key)){ 102 echo '<div class="notice notice-error"><p>'; 103 esc_html_e('Bitcoin Invoice Form: API Key is not set', 'coinsnap-bitcoin-invoice-form'); 104 echo '</p></div>'; 105 } 106 107 if(!empty($coinsnap_url) && !empty($coinsnap_api_key) && !empty($coinsnap_store_id)){ 108 109 // Create payment provider and get store data 110 $payment_provider = CoinsnapBIF_Util_Provider_Factory::payment_for_form( $form_id ); 111 $store = $payment_provider->get_store(); 112 113 try { 114 if ($store['code'] === 200){ 115 echo '<div class="notice notice-success"><p>'; 116 esc_html_e('Bitcoin Invoice Form: Established connection to ', 'coinsnap-bitcoin-invoice-form'); 117 echo esc_html($coinsnap_provider); 118 echo '</p></div>'; 119 120 if ( !$payment_provider->check_webhook() ) { 121 122 $register_webhook_result = $payment_provider->register_webhook(); 123 124 if (isset($register_webhook_result['error'])) { 125 echo '<div class="notice notice-error"><p>'; 126 esc_html_e('Bitcoin Invoice Form: Unable to create webhook on ', 'coinsnap-bitcoin-invoice-form'); 127 echo esc_html($coinsnap_provider); 128 echo '</p></div>'; 129 } 130 else { 131 $stored_webhook = get_option(AdminSettings::WEBHOOK_KEY, []); 132 $stored_webhook[$this->getPaymentProvider()] = [ 133 'id' => $register_webhook_result['result']['id'], 134 'secret' => $register_webhook_result['result']['secret'], 135 'url' => $register_webhook_result['result']['url'] 136 ]; 137 138 update_option(AdminSettings::WEBHOOK_KEY,$stored_webhook); 139 140 echo '<div class="notice notice-success"><p>'; 141 esc_html_e('Bitcoin Invoice Form: Successfully registered a new webhook on ', 'coinsnap-bitcoin-invoice-form'); 142 echo esc_html($coinsnap_provider); 143 echo '</p></div>'; 144 } 145 } 146 else { 147 echo '<div class="notice notice-info"><p>'; 148 esc_html_e('Bitcoin Invoice Form: Webhook already exists, skipping webhook creation', 'coinsnap-bitcoin-invoice-form'); 149 echo '</p></div>'; 150 } 151 } 152 } 153 catch (\Exception $e) { 154 echo '<div class="notice notice-error"><p>'; 155 esc_html_e('Bitcoin Invoice Form: API connection is not established', 'coinsnap-bitcoin-invoice-form'); 156 echo '</p></div>'; 157 } 158 } 159 } 160 } 161 162 public function btcpayApiUrlHandler(){ 163 164 } 165 166 public function coinsnapConnectionHandler(){ 167 168 $_nonce = filter_input(INPUT_POST,'apiNonce',FILTER_SANITIZE_FULL_SPECIAL_CHARS); 169 if ( !wp_verify_nonce( $_nonce, 'coinsnap-ajax-nonce' ) ) { 170 wp_die('Unauthorized!', '', ['response' => 401]); 171 } 172 173 $response = [ 174 'result' => false, 175 'message' => __('Coinsnap Bitcoin Invoice Form: Empty gateway URL or API Key', 'coinsnap-bitcoin-invoice-form') 176 ]; 177 178 179 $_provider = $this->getPaymentProvider(); 180 $post_id = ('' !== filter_input(INPUT_POST,'apiPost',FILTER_SANITIZE_FULL_SPECIAL_CHARS))? filter_input(INPUT_POST,'apiPost',FILTER_SANITIZE_FULL_SPECIAL_CHARS) : 0; 181 182 if($post_id > 0){ 183 $meta_payment = get_post_meta($post_id, '_coinsnapbif_payment', true); 184 $currency = $meta_payment['currency']; 185 } 186 else { 187 $currency = 'EUR'; 188 } 189 190 191 /* 192 193 $client = new Coinsnap_Paywall_Client(); 194 195 if($_provider === 'btcpay'){ 196 try { 197 198 $storePaymentMethods = $client->getStorePaymentMethods($this->getApiUrl(), $this->getApiKey(), $this->getStoreId()); 199 200 if ($storePaymentMethods['code'] === 200) { 201 if($storePaymentMethods['result']['onchain'] && !$storePaymentMethods['result']['lightning']){ 202 $checkInvoice = $client->checkPaymentData(0,$currency,'bitcoin','calculation'); 203 } 204 elseif($storePaymentMethods['result']['lightning']){ 205 $checkInvoice = $client->checkPaymentData(0,$currency,'lightning','calculation'); 206 } 207 } 208 } 209 catch (\Exception $e) { 210 $response = [ 211 'result' => false, 212 'message' => __('Coinsnap Bitcoin Paywall: API connection is not established', 'coinsnap-bitcoin-invoice-form') 213 ]; 214 $this->sendJsonResponse($response); 215 } 216 } 217 else { 218 $checkInvoice = $client->checkPaymentData(0,$currency,'coinsnap','calculation'); 219 } 220 221 if(isset($checkInvoice) && $checkInvoice['result']){ 222 $connectionData = __('Min order amount is', 'coinsnap-bitcoin-invoice-form') .' '. $checkInvoice['min_value'].' '.$currency; 223 } 224 else { 225 $connectionData = __('No payment method is configured', 'coinsnap-bitcoin-invoice-form'); 226 } 227 228 $_message_disconnected = ($_provider !== 'btcpay')? 229 __('Coinsnap Bitcoin Paywall: Coinsnap server is disconnected', 'coinsnap-bitcoin-invoice-form') : 230 __('Coinsnap Bitcoin Paywall: BTCPay server is disconnected', 'coinsnap-bitcoin-invoice-form'); 231 $_message_connected = ($_provider !== 'btcpay')? 232 __('Coinsnap Bitcoin Paywall: Coinsnap server is connected', 'coinsnap-bitcoin-invoice-form') : 233 __('Coinsnap Bitcoin Paywall: BTCPay server is connected', 'coinsnap-bitcoin-invoice-form'); 234 235 if( wp_verify_nonce($_nonce,'coinsnap-ajax-nonce') ){ 236 $response = ['result' => false,'message' => $_message_disconnected]; 237 238 try { 239 $this_store = $client->getStore($this->getApiUrl(), $this->getApiKey(), $this->getStoreId()); 240 241 if ($this_store['code'] !== 200) { 242 $this->sendJsonResponse($response); 243 } 244 245 else { 246 $response = ['result' => true,'message' => $_message_connected.' ('.$connectionData.')']; 247 $this->sendJsonResponse($response); 248 } 249 } 250 catch (\Exception $e) { 251 $response['message'] = __('Coinsnap Bitcoin Paywall: API connection is not established', 'coinsnap-bitcoin-invoice-form'); 252 } 253 254 $this->sendJsonResponse($response); 255 } 256 257 */ 258 $this->sendJsonResponse($response); 259 } 260 261 public function sendJsonResponse(array $response): void { 262 echo wp_json_encode($response); 263 exit(); 264 } 265 266 private function getPaymentProvider() { 267 $coinsnapbif_options = get_option('bif_settings', []); 268 $form_id = (filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ))? filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : 0; 269 270 if($form_id > 0){ 271 $payment = get_post_meta( $form_id, '_coinsnapbif_payment', true ); 272 $override = (is_array( $payment ) && ! empty( $payment['provider_override'] )) ? $payment['provider_override'] : ''; 273 } 274 275 $provider = (isset($override) && !empty($override)) ? $override : (($coinsnapbif_options['payment_provider'] === 'btcpay')? 'btcpay' : 'coinsnap'); 276 return $provider; 277 } 278 279 private function getApiKey() { 280 $coinsnapbif_options = get_option('bif_settings', []); 281 return ($this->getPaymentProvider() === 'btcpay')? $coinsnapbif_options['btcpay_api_key'] : $coinsnapbif_options['coinsnap_api_key']; 282 } 283 284 private function getStoreId() { 285 $coinsnapbif_options = get_option('bif_settings', []); 286 return ($this->getPaymentProvider() === 'btcpay')? $coinsnapbif_options['btcpay_store_id'] : $coinsnapbif_options['coinsnap_store_id']; 287 } 288 289 public function getApiUrl() { 290 $coinsnapbif_options = get_option('bif_settings', []); 291 return ($this->getPaymentProvider() === 'btcpay')? $coinsnapbif_options['btcpay_host'] : COINSNAP_SERVER_URL; 292 } 293 294 /** 295 * Register admin menus and submenus. 296 */ 297 public function register_admin_menu(): void { 72 298 add_menu_page( 73 299 __( 'Bitcoin Invoice Forms', 'coinsnap-bitcoin-invoice-form' ), … … 158 384 ) 159 385 ); 386 387 $post_id = (filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ))? filter_input(INPUT_GET,'post',FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : ''; 388 389 wp_localize_script('coinsnapbif-admin', 'coinsnapbif_ajax', array( 390 'ajax_url' => admin_url('admin-ajax.php'), 391 'nonce' => wp_create_nonce( 'coinsnap-ajax-nonce' ), 392 'post' => $post_id 393 )); 160 394 161 395 wp_enqueue_style( 'coinsnapbif-admin' );
Note: See TracChangeset
for help on using the changeset viewer.