@@ -36,6 +36,7 @@ public function __construct() {
3636 $ this ->seller_wallet = $ this ->get_option ('seller_wallet ' );
3737 $ this ->chain_id = $ this ->get_option ('chain_id ' );
3838 $ this ->token_address = $ this ->get_option ('token_address ' );
39+ $ this ->theme = $ this ->get_option ('theme ' , 'dark ' );
3940
4041 // Save settings hook
4142 add_action ('woocommerce_update_options_payment_gateways_ ' . $ this ->id , [$ this , 'process_admin_options ' ]);
@@ -95,6 +96,17 @@ public function init_form_fields() {
9596 'default ' => '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 ' , // USDC on Base
9697 'placeholder ' => __ ('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 ' , 'thirdweb-wc ' ),
9798 ],
99+ 'theme ' => [
100+ 'title ' => __ ('Widget Theme ' , 'thirdweb-wc ' ),
101+ 'type ' => 'select ' ,
102+ 'description ' => __ ('Choose the theme for the checkout widget. Default is dark. ' , 'thirdweb-wc ' ),
103+ 'default ' => 'dark ' ,
104+ 'options ' => [
105+ 'dark ' => __ ('Dark ' , 'thirdweb-wc ' ),
106+ 'light ' => __ ('Light ' , 'thirdweb-wc ' ),
107+ ],
108+ 'desc_tip ' => true ,
109+ ],
98110 ];
99111 }
100112
@@ -119,28 +131,26 @@ public function payment_fields() {
119131 $ params ['tokenAddress ' ] = $ this ->token_address ;
120132 }
121133
134+ // Add theme (default is dark, but allow override)
135+ $ params ['theme ' ] = $ this ->theme ;
136+
122137 $ iframe_url = 'https://thirdweb.com/bridge/checkout-widget? ' . http_build_query ($ params );
123138
124139 echo '<div id="thirdweb-checkout-widget"> ' ;
125140 echo '<iframe src=" ' . esc_url ($ iframe_url ) . '" height="700px" width="100%" style="border: 0;" title="thirdweb Checkout Widget"></iframe> ' ;
126141 echo '</div> ' ;
127-
128- // Hidden field to store transaction hash
129- echo '<input type="hidden" name="thirdweb_tx_hash" id="thirdweb_tx_hash" value="" /> ' ;
130142 }
131143
132144 /**
133145 * Validate payment fields
134146 *
135147 * Note: For WooCommerce Blocks, validation happens in the React component.
136- * This method is mainly for legacy checkout. We allow empty tx_hash because
137- * the checkout widget confirms payment before sending success message.
148+ * This method is mainly for legacy checkout.
138149 */
139150 public function validate_fields () {
140151 // Always return true - validation is handled by:
141152 // 1. React component for Blocks (checks paymentComplete before allowing submission)
142153 // 2. Frontend JavaScript for legacy checkout
143- // Empty tx_hash is OK - widget confirms payment before sending success message
144154 return true ;
145155 }
146156
@@ -150,55 +160,31 @@ public function validate_fields() {
150160 public function process_payment ($ order_id ) {
151161 $ order = wc_get_order ($ order_id );
152162
153- // Get payment data - WooCommerce Blocks sends it in payment_data array
154- $ tx_hash = '' ;
155- $ chain_id = '' ;
163+ // Get chain ID from payment data (WooCommerce Blocks sends it in payment_data array)
164+ $ chain_id = $ this ->chain_id ;
156165
157- // Try to get from Blocks format first
158166 if (isset ($ _POST ['payment_data ' ]) && is_array ($ _POST ['payment_data ' ])) {
159167 foreach ($ _POST ['payment_data ' ] as $ data ) {
160- if (isset ($ data ['key ' ])) {
161- if ($ data ['key ' ] === 'thirdweb_tx_hash ' ) {
162- $ tx_hash = sanitize_text_field ($ data ['value ' ] ?? '' );
163- }
164- if ($ data ['key ' ] === 'thirdweb_chain_id ' ) {
165- $ chain_id = sanitize_text_field ($ data ['value ' ] ?? '' );
166- }
168+ if (isset ($ data ['key ' ]) && $ data ['key ' ] === 'thirdweb_chain_id ' ) {
169+ $ chain_id = sanitize_text_field ($ data ['value ' ] ?? $ this ->chain_id );
170+ break ;
167171 }
168172 }
169173 }
170174
171175 // Fallback to legacy format
172- if (empty ($ tx_hash )) {
173- $ tx_hash = sanitize_text_field ($ _POST ['thirdweb_tx_hash ' ] ?? '' );
174- }
175- if (empty ($ chain_id )) {
176- $ chain_id = sanitize_text_field ($ _POST ['thirdweb_chain_id ' ] ?? $ this ->chain_id );
176+ if ($ chain_id === $ this ->chain_id && isset ($ _POST ['thirdweb_chain_id ' ])) {
177+ $ chain_id = sanitize_text_field ($ _POST ['thirdweb_chain_id ' ]);
177178 }
178179
179- // Payment was completed via checkout widget (frontend confirmed success)
180- // Transaction hash is optional - thirdweb widget confirms payment before sending success
181- if (!empty ($ tx_hash )) {
182- // Try to verify on-chain (non-blocking)
183- $ verified = $ this ->verify_transaction ($ tx_hash , $ order );
184- $ order ->payment_complete ($ tx_hash );
185- $ order ->add_order_note (
186- sprintf (
187- __ ('Stablecoin payment completed via thirdweb checkout. Transaction: %s (Chain: %s) ' , 'thirdweb-wc ' ),
188- $ tx_hash ,
189- $ chain_id ?: $ this ->chain_id
190- )
191- );
192- } else {
193- // No transaction hash - payment completed via widget, trust thirdweb's confirmation
194- $ order ->payment_complete ();
195- $ order ->add_order_note (
196- sprintf (
197- __ ('Stablecoin payment completed via thirdweb checkout widget. Chain: %s ' , 'thirdweb-wc ' ),
198- $ chain_id ?: $ this ->chain_id
199- )
200- );
201- }
180+ // Payment was completed via checkout widget - trust thirdweb's confirmation
181+ $ order ->payment_complete ();
182+ $ order ->add_order_note (
183+ sprintf (
184+ __ ('Stablecoin payment completed via thirdweb checkout widget. Chain: %s ' , 'thirdweb-wc ' ),
185+ $ chain_id
186+ )
187+ );
202188
203189 WC ()->cart ->empty_cart ();
204190
@@ -208,51 +194,6 @@ public function process_payment($order_id) {
208194 ];
209195 }
210196
211- /**
212- * Verify transaction on-chain
213- */
214- private function verify_transaction ($ tx_hash , $ order ) {
215- // Use public RPC endpoint to verify the transaction
216- // No Client ID needed - using public RPC endpoints
217- $ rpc_endpoints = [
218- '1 ' => 'https://eth.llamarpc.com ' , // Ethereum
219- '8453 ' => 'https://base.llamarpc.com ' , // Base
220- '137 ' => 'https://polygon.llamarpc.com ' , // Polygon
221- '42161 ' => 'https://arbitrum.llamarpc.com ' , // Arbitrum
222- '10 ' => 'https://optimism.llamarpc.com ' , // Optimism
223- ];
224-
225- $ rpc_url = $ rpc_endpoints [$ this ->chain_id ] ?? 'https://eth.llamarpc.com ' ;
226-
227- $ response = wp_remote_post ($ rpc_url , [
228- 'headers ' => ['Content-Type ' => 'application/json ' ],
229- 'body ' => json_encode ([
230- 'jsonrpc ' => '2.0 ' ,
231- 'method ' => 'eth_getTransactionReceipt ' ,
232- 'params ' => [$ tx_hash ],
233- 'id ' => 1 ,
234- ]),
235- 'timeout ' => 10 ,
236- ]);
237-
238- if (is_wp_error ($ response )) {
239- // If RPC fails, still allow the order (transaction hash is recorded)
240- // Admin can manually verify on block explorer
241- return true ;
242- }
243-
244- $ body = json_decode (wp_remote_retrieve_body ($ response ), true );
245- $ receipt = $ body ['result ' ] ?? null ;
246-
247- if (!$ receipt || $ receipt ['status ' ] !== '0x1 ' ) {
248- return false ;
249- }
250-
251- // Additional verification: check recipient and amount in logs
252- // This is simplified - production code should decode transfer events
253- return true ;
254- }
255-
256197 /**
257198 * Get config for frontend
258199 */
@@ -261,6 +202,7 @@ public function get_frontend_config() {
261202 'seller ' => $ this ->seller_wallet ,
262203 'chainId ' => (int ) $ this ->chain_id ,
263204 'tokenAddress ' => $ this ->token_address ,
205+ 'theme ' => $ this ->theme ,
264206 'title ' => $ this ->title ,
265207 'description ' => $ this ->description ,
266208 ];
0 commit comments