为了在 antom-payments 插件中集成 Boost 支付通道，同时保持原有目录结构不变，请按以下步骤操作：1. 添加前端资源文件1.1 在 assets/blocks/ 下创建 boost 目录：assets/blocks/boost/ ├── boost.asset.php └── boost.js从现有通道（如 alipay_cn）复制模板文件，修改类名和标识符为 boost。1.2 在 assets/images/ 下添加 Boost 图标：assets/images/Boost-A+.svg # 符合命名规范（如 Alipay-A+.svg）2. 添加后端网关类在 includes/gateways/ 下创建文件：includes/gateways/class-wc-gateway-antom-boost.php文件内容示例（基于 class-wc-gateway-antom-alipay-cn.php 修改）：3. 添加区块支持类在 includes/blocks/ 下创建文件：includes/blocks/class-wc-gateway-antom-boost-block-support.php文件内容示例（基于其他通道修改）：4. 添加资源目录脚本在 resource/ 下创建文件：resource/boost.js从 resource/alipay_cn.js 复制模板，替换内容标识为 boost。5. 注册网关到核心系统修改主文件 includes/antom-payment-gateway-settings.php： array( 'gateway_file' => $dir . '/gateways/class-wc-gateway-antom-boost.php', 'gateway_class' => 'WC_Gateway_Antom_Boost', 'block_file' => $dir . '/blocks/class-wc-gateway-antom-boost-block-support.php', 'block_support_class' => 'WC_Gateway_Antom_Boost_Block_Support', 'slug' => 'antom_gcash', 'default_display_name' => 'Boost', 'menu_title' => __( 'Boost', 'antom-payments' ) . ' ' . __( 'Settings', 'antom-payments' ), 'pay_name' => __( 'Boost by Antom', 'antom-payments' ), 'payment_method_type' => 'BOOST', 'support_currencies' => array( 'AED', 'CHF', 'HKD', 'QAR', 'EUR', 'DKK', 'USD', 'CAD', 'CNY', 'THB', 'AUD', 'SGD', 'JPY', 'PLN', 'GBP', 'NZD', 'PHP', 'TRY' ), 'icon' => ANTOM_PAYMENT_GATEWAYS_URL . 'assets/images/Boost-A+.svg', ),关键注意事项ID 一致性：网关类中的 $id（antom_boost）区块支持类中的 $gateway_id（antom_boost）资源文件名（boost.js）图标规范：SVG 文件命名为 Boost-A+.svg，与其他通道统一。区块注册：确保 includes/class-antom-frontend.php 中的区块注册逻辑自动加载 boost 目录（已有逻辑通常无需修改）。测试验证：在 WooCommerce 后台启用 Boost 支付方式。测试下单流程，检查支付表单是否正常渲染。通过以上步骤，Boost 通道即可无缝集成到现有插件中，且完全符合原有目录结构。
前沿对接第三方支付的过程中，有几个字段需要客户端上传。需要在checkout页面让客户输入然后提交。{card-default label="样式" width="75%"}{/card-default}代码上述样式的自定义代码{hide}// 添加自定义字段到结账页面 add_action('woocommerce_after_order_notes', 'custom_checkout_fields'); function custom_checkout_fields($checkout) { echo ' ' . __('Custom Fields') . ' '; woocommerce_form_field('cardNo', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Card Number'), 'required' => true ), $checkout->get_value('cardNo')); woocommerce_form_field('cardExpireMonth', array( 'type' => 'text', 'class' => array('form-row-first'), 'label' => __('Card Expiry Month'), 'required' => true ), $checkout->get_value('cardExpireMonth')); woocommerce_form_field('cardExpireYear', array( 'type' => 'text', 'class' => array('form-row-last'), 'label' => __('Card Expiry Year'), 'required' => true ), $checkout->get_value('cardExpireYear')); woocommerce_form_field('cardSecurityCode', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Security Code'), 'required' => true ), $checkout->get_value('cardSecurityCode')); woocommerce_form_field('cardType', array( 'type' => 'select', 'class' => array('form-row-wide'), 'label' => __('Card Type'), 'options' => array( 'visa' => __('VISA'), 'mastercard' => __('MASTERCARD'), 'ae' => __('AE') ), 'required' => true ), $checkout->get_value('cardType')); echo ' '; } // 验证并保存输入的值 add_action('woocommerce_checkout_process', 'custom_checkout_fields_validation'); function custom_checkout_fields_validation() { if (empty($_POST['cardNo'])) { wc_add_notice(__('Card Number is a required field.'), 'error'); } if (empty($_POST['cardExpireMonth'])) { wc_add_notice(__('Card Expiry Month is a required field.'), 'error'); } if (empty($_POST['cardExpireYear'])) { wc_add_notice(__('Card Expiry Year is a required field.'), 'error'); } if (empty($_POST['cardSecurityCode'])) { wc_add_notice(__('Security Code is a required field.'), 'error'); } if (empty($_POST['cardType']) || $_POST['cardType'] == '') { wc_add_notice(__('Card Type is a required field.'), 'error'); } } // 保存输入的值 add_action('woocommerce_checkout_update_order_meta', 'save_custom_checkout_fields'); function save_custom_checkout_fields($order_id) { if (!empty($_POST['cardNo'])) { update_post_meta($order_id, 'Card Number', sanitize_text_field($_POST['cardNo'])); } if (!empty($_POST['cardExpireMonth'])) { update_post_meta($order_id, 'Card Expiry Month', sanitize_text_field($_POST['cardExpireMonth'])); } if (!empty($_POST['cardExpireYear'])) { update_post_meta($order_id, 'Card Expiry Year', sanitize_text_field($_POST['cardExpireYear'])); } if (!empty($_POST['cardSecurityCode'])) { update_post_meta($order_id, 'Security Code', sanitize_text_field($_POST['cardSecurityCode'])); } if (!empty($_POST['cardType'])) { update_post_meta($order_id, 'Card Type', wc_clean($_POST['cardType'])); } } {/hide}
前言做跨境电商如何收款是所有商家都需要关注的。自由度最高的是基于wordpress的外贸独立站，独立站建好以后需要对接收款通道。easylink是香港的支付通道。下面分享对接过程。{card-default label="支付引导" width="75%"}{/card-default}支付流程交易流程是指访问网站的客户从选择商品下单到支付成功的整个流程。{card-default label="支付流程" width="80%"}{/card-default}插件开发熟悉整个流程后，就要根据通道提供的接口文档编写代码。代码编写的主要模块有签名函数，有订单提交，异步通知处理，同步跳转函数等。签名本通道采用sha256加密方式function buildMysign($sort_para, $key, $sign_type = "MD5") { $prestr = createLinkstring ( $sort_para ); $prestr = $prestr .'&'. $key; $mysgin = sign ( $prestr, $sign_type ); return $mysgin; } function createLinkstring($para) { $arg = ""; foreach ($para as $key => $val) { if ($key == "accessKey" || $key == "merchantCardNumber" || $key == "BankId" || $key == "merReserved") continue; else $arg .= $key . "=" . $val . "&"; } $arg = rtrim($arg, '&'); return $arg; } function paraFilter($para) { $para_filter = array (); foreach ($para as $key => $val) { $para_filter [$key] = $para [$key]; } return $para_filter; } function argSort($para) { ksort ( $para ); reset ( $para ); return $para; } function sign($prestr, $sign_type = 'MD5') { $sign = ''; $sign = hash($sign_type, $prestr); return $sign; }订单提交订单提交是组织好官方需要的字段，通过api接口提交并获取结果class Submit { function buildRequestPara($para_temp) { $key = '********'; $sign_method = 'SHA256'; $para_filter = paraFilter($para_temp); $para_sort = argSort($para_filter); $mysign = buildMysign($para_sort, trim($key), strtoupper(trim($sign_method))); $para_sort['accessKey'] = $mysign; return $para_sort; } function getMsg($para_temp, $gateway) { $respondData = ''; $para = $this->buildRequestPara($para_temp); $ch = curl_init ($gateway); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ( $ch, CURLOPT_BINARYTRANSFER, true); curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt ( $ch, CURLOPT_POSTFIELDS, $para); $output = curl_exec ( $ch ); curl_close ( $ch ); $respondData = json_decode($output); return $respondData; } }异步通知在用户支付成功后，通道会主动发起支付成功的通知到网站。需要专门的函数来处理支付结果。 function check_easylink_ipn_response() { global $woocommerce, $wpdb; require_once("lib/notify.class.php"); if (($_SERVER['REQUEST_METHOD'] === 'POST') && preg_match("/wc_easylink_notify/i", $_SERVER['REQUEST_URI'])) { $Notify = new Notify(); $verify_result = $Notify->verifyNotify(); if ( $verify_result ) { if ($_POST["respCode"] != "00") { error_log(__METHOD__ . PHP_EOL . $_POST["respMsg"]); } elseif ( $_POST['status'] == '1' ) { $sref = $_POST['paymentId']; $statustr = $this->easylink_processing; $check_query = $wpdb->get_results("SELECT order_id,order_state,mref FROM {$wpdb->prefix}easylink_data WHERE sref = '".addslashes($sref)."'", ARRAY_A); $check_query_count = count($check_query); if( $check_query_count >= 1 ) { if($check_query[0]['order_state'] == 'I') { $query = "update {$wpdb->prefix}easylink_data set order_state='C' where sref='".addslashes($sref)."'"; $wpdb->query($query); $inv_id = $check_query[0]['order_id']; $mref = $check_query[0]['mref']; $order = new WC_Order($inv_id); $order->update_status($statustr, __('Order has been paid by ID: ' . $mref, 'easylink-for-woocommerce')); wc_reduce_stock_levels( $order->get_id() ); add_post_meta( $inv_id, '_paid_date', current_time('mysql'), true ); update_post_meta( $inv_id, '_transaction_id', wc_clean($mref) ); $order->payment_complete(wc_clean($mref)); $woocommerce->cart->empty_cart(); } } } } //接口返回 exit('success'); } }同步跳转在网站处理支付成功的消息的同时，客户浏览器需要跳转到支付成功页面。function check_easylink_return() { global $woocommerce, $wpdb; if (($_SERVER['REQUEST_METHOD'] === 'GET') && preg_match("/wc_easylink_return/i", $_SERVER['REQUEST_URI'])) { //error_log(__METHOD__ . PHP_EOL .print_r($_GET, true)); $mref = $_GET['mref']; sleep(1); $check_query = $wpdb->get_results("SELECT order_id,order_state FROM {$wpdb->prefix}easylink_data WHERE mref = '".addslashes($mref)."'", ARRAY_A); $check_query_count = count($check_query); if($check_query_count >= 1){ $inv_id = $check_query[0]['order_id']; $inv_state = $check_query[0]['order_state']; switch ( $inv_state ) { case 'C': $order = new WC_Order($inv_id); wp_redirect(esc_url_raw(add_query_arg('key', $order->get_order_key(), add_query_arg('order-received', $inv_id, $this->get_return_url($order))))); break; default: wp_redirect( wc_get_cart_url() ); } exit; } } wp_redirect(home_url()); }完整的支付插件【支付插件】woocommerce对接香港支付通道easylink插件设置插件安装通过wordpress的后台页面上传然后激活即可，设置也非常简单。{card-default label="插件设置" width="80%"}{/card-default}
前言用wordpress+woocommerce做跨境独立站的朋友为了顺利收款，会对接各种国外的本地收款渠道。主流的用paypal等，不过通道越大。合规查的越严，小众的一些三方或四方通道，限制也会小一点。本文分享菲律宾四方通道okpay的对接过程。{card-default label="收银台" width="75%"}{/card-default}对接流程一般都是申请通道账号，根据接口文档开发插件，然后测试调试，通过后上线。支付插件主要有三个函数和签名函数。三个函数为提交订单信息获取支付链接，异步通知处理，同步跳转处理函数。核心代码md5签名函数 public function get_sign($srcArray, $merKey){ if(null == $srcArray){ return "123456"; } //先干掉sign字段 $keys = array_keys($srcArray); $index = array_search("sign", $keys); if ($index !== FALSE) { array_splice($srcArray, $index, 1); } //对数组排序 ksort($srcArray); //生成待签名字符串 $srcData = ""; foreach ($srcArray as $key => $val) { if($val === null || $val === "" ){ //值为空的跳过，不参与加密 continue; } $srcData .= "$key=$val" . "&"; } $srcData = substr($srcData, 0, strlen($srcData) - 1); //生成签名字符串 $sign = md5($srcData.$merKey); return $sign; }post提交函数 public function http_post($url, $sendInfo) { try { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); curl_setopt($ch, CURLOPT_TIMEOUT, 60); // Set headers for JSON content curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Accept: application/json' )); // Encode $sendInfo as JSON $json_data = json_encode($sendInfo); curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data); $curl_result = curl_exec($ch); curl_close($ch); return $curl_result; } catch (Exception $e) { return null; } }支付成功后异步回调处理函数 if (($_SERVER['REQUEST_METHOD'] === 'POST') && preg_match("/wc_okpay_notify/i", $_SERVER['REQUEST_URI'])) { $response = file_get_contents("php://input"); error_log(__METHOD__ . PHP_EOL .print_r($response, true)); //参数 $respj = json_decode($response, true, 512, JSON_BIGINT_AS_STRING); //error_log(__METHOD__ . PHP_EOL .print_r($respj['data'], true)); if ($respj['data']) { //组织签名串 //$res_sign = $this->get_sign($_POST, $this->okpay_merchant_key); #订单号 $mref = $respj['data']['orderNo']; $sref = $respj['data']['businessNo'];; #写入数据库 $query = "update {$wpdb->prefix}okpay_data set order_state = 'C' where mref = '".addslashes($mref)."'"; $wpdb->query($query); #后续处理 $check_query = $wpdb->get_results("SELECT order_id FROM {$wpdb->prefix}okpay_data WHERE mref = '".addslashes($mref)."'", ARRAY_A); $check_query_count = count($check_query); if($check_query_count >= 1){ $order_id= $check_query[0]['order_id']; $order = new WC_Order($order_id); $statustr = $this->okpay_processing; $order->update_status($statustr, __('Order has been paid by ID: ' . $sref, 'okpay-for-woocommerce')); wc_reduce_stock_levels( $order->get_id() ); add_post_meta( $order_id, '_paid_date', current_time('mysql'), true ); update_post_meta( $order_id, '_transaction_id', wc_clean($order_id) ); $order->payment_complete(wc_clean($order_id)); $woocommerce->cart->empty_cart(); } }项目完整代码【支付插件】woocommerce对接第三方支付接口okpay
前言用wordpress+woocommerce做跨境独立站的朋友为了顺利收款，会对接各种国外的本地收款渠道。主流的用paypal等，不过通道越大。合规查的越严，小众的一些三方或四方通道，限制也会小一点。本文分享巴西通道hambit的对接过程。{card-default label="订单页" width="75%"}{/card-default}接口文档地址对接流程一般都是申请通道账号，根据接口文档开发插件，然后测试调试，通过后上线。{card-default label="流程" width="80%"}{/card-default}核心代码组织获取支付url的参数 $Body = array( "amount" => $amount, "channelType" => "PIX", "externalOrderId" => $mref, "notifyUrl" => $notify_url, "remark" => "USER", "returnUrl" => $return_url, "inputCpf" => 0 ); $sign_arr = $Body; $sign_arr['access_key'] = $AccessKey; $sign_arr['timestamp'] = $timestamp; $sign_arr['nonce'] = $uuid_str; $sign_str = $this->get_sign($sign_arr, $this->hambit_secret_key); //请求头 $Headers = array( 'Content-Type' => 'application/json;charset=utf-8', 'access_key' => $AccessKey, 'timestamp' => $timestamp, 'nonce' => $uuid_str, 'sign' => $sign_str );提交参数，获取url $req_api = $this->req_api.'/api/v3/bra/createCollectingOrder'; $postData = json_encode($Body); //打印参数 error_log(__METHOD__ . PHP_EOL .print_r($Body, true)); $args = array( 'headers' => $Headers, 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'body' => $postData, ); // 提交参数 $postRequest = wp_remote_post($req_api, $args); if ($postRequest['response']['code'] === 200) { $result = json_decode($postRequest['body'], true); } else { error_log(__METHOD__ . PHP_EOL . 'Code:' . $postRequest['response']['code'] . PHP_EOL. ' Error:' . $postRequest['response']['message']); //抛出异常 throw new Exception("Unable to reach hambit Payments (" . $postRequest['response']['message'] . ")"); } error_log(__METHOD__ . PHP_EOL .print_r($result, true)); //结果处理 if (($result['code'] =='200') && ($result['msgEn'] =='SUCCESS')) { //写入数据库 $query = "insert into {$wpdb->prefix}hambit_data (mref, order_id, total_cost, currency, order_state, timestamp) values ('".$mref."', '". $order_id . "',".$amount.",'". $currency_code."','I', now())"; $wpdb->query($query); //支付链接 $PayUrl = $result['data']['cashierUrl']; //跳转payurl return array( 'result' => 'success', 'redirect' => $PayUrl ); } else { error_log(__METHOD__ .PHP_EOL. print_r($result, true)); throw new Exception("Unable to redirect payurl (" . $result['msg'] . ")"); }支付成功后异步处理 if (($_SERVER['REQUEST_METHOD'] === 'POST') && preg_match("/wc_hambit_notify/i", $_SERVER['REQUEST_URI'])) { //接收post json的数据 $response = file_get_contents("php://input"); error_log(__METHOD__ . PHP_EOL .print_r($response, true)); //参数 $respj = json_decode($response, true, 512, JSON_BIGINT_AS_STRING); //判断 if ($respj['orderStatus'] == 'Completed') { #订单号 $mref = $respj['externalOrderId']; $sref = $respj['orderId']; #写入数据库 $query = "update {$wpdb->prefix}hambit_data set order_state = 'C' where mref = '".addslashes($mref)."'"; $wpdb->query($query); #后续处理 $check_query = $wpdb->get_results("SELECT order_id FROM {$wpdb->prefix}hambit_data WHERE mref = '".addslashes($mref)."'", ARRAY_A); $check_query_count = count($check_query); if($check_query_count >= 1){ $order_id= $check_query[0]['order_id']; $order = new WC_Order($order_id); $statustr = $this->hambit_processing; $order->update_status($statustr, __('Order has been paid by ID: ' . $sref, 'hambit-for-woocommerce')); wc_reduce_stock_levels( $order->get_id() ); add_post_meta( $order_id, '_paid_date', current_time('mysql'), true ); update_post_meta( $order_id, '_transaction_id', wc_clean($order_id) ); $order->payment_complete(wc_clean($order_id)); $woocommerce->cart->empty_cart(); } } //接口返回 $return_resp = array( "code" => 200, "success" => true ); $jsonResponse = json_encode($return_resp); exit($jsonResponse); }项目完整代码【支付插件】woocommerce对接第三方支付接口hambit
第三方支付HKPay接口对接过程要点总结
前言HKPay是香港的一条支付通道，可用于外贸独立站做境外电商收款。{card-default label="支付后台" width="75%"}{/card-default}核心函数所有支付通道的对接流程，几乎都是一样的。一般都是组织参数、签名、提交然后处理返回结果。然后跳转到收银页面，等待用户支付。用户支付后，返回网站。同时异步接口接收结果通知并处理。字符串拼接函数计算md5签名之前，用到的字符串拼接函数。 //拼接字符串 public function param_ck_null($kq_va,$kq_na) { if($kq_va == ""){ $kq_va=""; }else{ return $kq_va=$kq_na.'='.$kq_va.'&'; } }数据提交函数采用post/json提交方式 //提交数据到上游接口函数 public function send_post_request($url, $body, $headers, $method) { $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_POSTFIELDS => json_encode($body), CURLOPT_HTTPHEADER => $headers, )); $response = curl_exec($curl); curl_close($curl); return $response; }获取订单结果url用户支付之后，不管成功还是失败都需要跳转回到网站。此函数用于获取返回网站需要的网址。 //获取订单结果url public function get_order_checkout_url($orderid) { //完成支付url $rurl = WC()->api_request_url( 'wc_hkpay_return' ) ; $check = strpos($rurl, '?'); if ( $check !== false) { $rurl = $rurl . "&mref=" . $orderid; } else { $rurl = $rurl . "?mref=" . $orderid; } return $rurl; }展示支付二维码返回的是二维码数据，需要在网站上展示 function generate_form($order_id) { $html_str = ''; global $wpdb; $order = wc_get_order($order_id); //url查询 $check_query = $wpdb->get_results("SELECT ref,paydata,paytype FROM {$wpdb->prefix}hkpay_data WHERE orderid = '".addslashes($order_id)."' order by id desc", ARRAY_A); $check_query_count = count($check_query); if($check_query_count >= 1){ $mref = $check_query[0]['ref']; $paydata = $check_query[0]['paydata']; $paytype = $check_query[0]['paytype']; $completed_url = $this->get_order_checkout_url($mref); if ($paytype ==='800201') { $html_str = 'Scan the QR code to complete the payment'. ' '. ' '. ' '. ' '. ''.__('Pay Completed', 'uepay-for-woocommerce').''. 'get_cancel_order_url().'">'.__('Cancel', 'uepay-for-woocommerce').''. ' '; } } return $html_str; }提交订单并处理返回获取支付链接，并处理返回 $response = $this->send_post_request($req_api, $Body, $Headers, 'POST'); $result = json_decode($response); //打印结果 //error_log(__METHOD__ . PHP_EOL .print_r($result, true)); if ($result->code != 0 ) { error_log(__METHOD__ . PHP_EOL . 'Code:' . $result->code . PHP_EOL. ' Error:' . $result->msg); //抛出异常 throw new Exception("Unable to reach hkpay Payments (" . $result->msg . ")"); } if ($result->code == 0 ) { $OrderNo = $result->data->payOrderId; $paydata = $result->data->payData; #写入数据库 $query = "insert into {$wpdb->prefix}hkpay_data (ref, ordercode, orderid, total_cost, currency, paydata, paytype, order_state, timestamp) values ('".$mref."', '".$OrderNo."','". $order_id . "',".$amount.",'". $currency_code."','". $paydata ."','".$payType."','I', now())"; $wpdb->query($query); //跳转payurl return array( 'result' => 'success', 'redirect' => esc_url_raw(add_query_arg('order-pay', $order->get_id(), add_query_arg('key', $order->get_order_key(), wc_get_page_permalink( 'checkout' )))) ); } else { error_log(__METHOD__ . PHP_EOL . 'Code:' . $result->code . PHP_EOL. ' Error:' . $result->msg); throw new Exception("Unable to redirect payurl (" . $result->msg . ")"); }完整支付插件【支付插件】woocommerce对接hkpay三方支付接口
前言开发woocommerce批量发布商品插件的过程中，需要通过代码的形式将商品发布。分享用到的核心代码。包括商品创建、图片下载上传、变体商品添加。调试了好久，终于搞定。{card-default label="工具页面" width="85%"}{/card-default}核心代码图片下载并上传媒体库收到的产品链接，有时候不是标准链接，自己加上处理过程。//图片处理函数 function download_and_import_imgs($img_arr) { $gallery_image_ids = []; //图片批量下载并导入 foreach ($img_arr as $image_url) { //协议头处理 if (!preg_match("~^(?:f|ht)tps?://~i", $image_url)) { $image_url = 'https:' . $image_url; } //删掉?号后部分 if (strpos($image_url, '?') !== false) { $parsedUrl = parse_url($image_url); $image_url = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . $parsedUrl['path']; } // 下载图像并获取本地路径 $temp_file = download_url($image_url); if (!is_wp_error($temp_file)) { //文件名处理 $filename=basename($image_url); $extension = pathinfo($filename, PATHINFO_EXTENSION); if ($extension =='') { $filename = $filename.'.jpg'; } $file_array = array( 'name' => $filename, 'tmp_name' => $temp_file ); // 将图像添加到媒体库 $attachment_id = media_handle_sideload($file_array, 0); if (!is_wp_error($attachment_id)) { $gallery_image_ids[] = $attachment_id; } else { $err_msg = $temp_file->get_error_message(); error_log(__METHOD__ . PHP_EOL .print_r('添加媒体库:'.$err_msg, true)); } } else { $err_msg = $temp_file->get_error_message(); error_log(__METHOD__ . PHP_EOL .print_r('下载图片:'.$err_msg, true)); } } //返回 return $gallery_image_ids; }创建产品产品分为单体产品和变体产品if (($_SERVER['REQUEST_METHOD'] === 'POST') && preg_match("/pimport/i", $_SERVER['REQUEST_URI'])) { // 获取 POST 请求的原始数据 $postData = file_get_contents('php://input'); // 解码 JSON 数据为关联数组 $jsonData = json_decode($postData, true); //打印日志 //error_log(__METHOD__ . PHP_EOL .print_r($jsonData, true)); // 使用 isset() 函数检查是否存在特定的表单字段 if (isset($jsonData['unique_id']) && isset($jsonData['mall_info'])) { $unique_id = $jsonData['unique_id']; $mall_info = $jsonData['mall_info']; // 进一步处理接收到的数据 // 商品名称 if (array_key_exists('name', $mall_info)) { $product_name = $mall_info['name']; } else { exit('fail'); } // 获取商品sku信息 if (array_key_exists('skus', $mall_info)) { $sku_arr=$mall_info['skus']; //多sku产品 } else { $sku_arr = []; } switch (count($sku_arr)) { //未获取sku信息 case 0: $product_type = 'simple'; //自定义sku $sku = generate_random_sku(); // price if (array_key_exists('price', $mall_info)) { $regular_price = $mall_info['price']; $sale_price = number_format($regular_price*0.9,2); // 商品状态 $status = 'publish'; } else { $regular_price = 0; $sale_price = 0; // 商品状态 $status = 'draft'; } if (array_key_exists('quantity', $mall_info)) { $quantity = $mall_info['quantity']; }else{ // 设置商品库存数量 $quantity = rand(10,100); } break; //单规格商品 case 1: $product_type = 'simple'; $sku = $sku_arr[0]['skuId']; if (array_key_exists('price', $sku_arr[0])) { $regular_price = $sku_arr[0]['price']; $sale_price = number_format($regular_price*0.9,2); // 商品状态 $status = 'publish'; } else { $regular_price = 0; $sale_price = 0; // 商品状态 $status = 'draft'; } if (array_key_exists('quantity', $sku_arr[0])) { $quantity = $mall_info['quantity']; }else{ // 设置商品库存数量 $quantity = rand(10,100); } break; //组合商品 default: $product_type = 'variable'; $sku = generate_random_sku(); if (array_key_exists('price', $sku_arr[0])) { $regular_price = $sku_arr[0]['price']; $sale_price = number_format($regular_price*0.9,2); // 商品状态 $status = 'publish'; } else { $regular_price = 0; $sale_price = 0; // 商品状态 $status = 'draft'; } if (array_key_exists('quantity', $sku_arr[0])) { $quantity = $sku_arr[0]['quantity']; }else{ // 设置商品库存数量 $quantity = rand(10,100); } } if ($product_type=='simple') { //创建产品 $product = new WC_Product(); }else{ //创建产品 $product = new WC_Product_Variable(); } // 设置商品 SKU $product->set_sku($sku); // 设置名称 $product->set_name($product_name); // 常规价格,促销价格 $product->set_regular_price($regular_price); $product->set_sale_price($sale_price); // 库存 $product->set_stock_quantity($quantity); // 产品相册 if (array_key_exists('imgs', $mall_info)) { $image_ids=download_and_import_imgs($mall_info['imgs']); //图片大于0 if (count($image_ids)>0) { // 设置商品图像 $product->set_image_id($image_ids[0]); // 设置产品相册图像 $product->set_gallery_image_ids($image_ids); } else { $stauts = 'draft'; } } // 正文图片 if (array_key_exists('descimgs', $mall_info)) { $descimgs = $mall_info['descimgs']; //下载图片并获取id列表 $desc_image_ids=download_and_import_imgs($mall_info['descimgs']); } // 正文描述 if (array_key_exists('desc', $mall_info)) { $description = $mall_info['desc']; //处理description } else { if (count($desc_image_ids)>0) { $description = ''; foreach ($desc_image_ids as $image_id) { // 获取新上传图片的 URL $new_image_url = wp_get_attachment_url($image_id); // 将新图片的 HTML 标记添加到描述中 $new_image_html = ' '; $description .= $new_image_html; } }else{ $description = ''; } } if(isset($description)) { // 设置更新后的描述 $product->set_description($description); } // 设置产品分类 $table_name = $wpdb->prefix . 'batch_upload_job'; $query = $wpdb->prepare("SELECT category FROM $table_name WHERE unique_id = %s", $unique_id); $category = $wpdb->get_var($query); $category_ids = array($category,); $product->set_category_ids($category_ids); // 设置商品状态 $product->set_status($status); // 创建 $product_id = $product->save(); // 多sku处理 if ($product_type=='variable') { // 添加自定义属性 $attribute_name = sanitize_title( 'pa_spec'.$product_id ); $attribute_label = ucfirst( $attribute_name ); if ( ! taxonomy_exists( $attribute_name ) ) { // 创建新属性 $attribute_id = wc_create_attribute( array( 'name' => $attribute_name, 'label' => $attribute_label, 'slug' => $attribute_name, 'type' => 'select', 'order_by' => 'menu_order', 'has_archives' => true ) ); // 将属性关联到产品类型上 register_taxonomy( $attribute_name, apply_filters( 'woocommerce_taxonomy_objects_' . $attribute_name, array( 'product' ) ), apply_filters( 'woocommerce_taxonomy_args_' . $attribute_name, array( 'labels' => array(), 'hierarchical' => false, 'show_ui' => false, 'query_var' => true, 'rewrite' => false, ) ) ); } foreach ( $sku_arr as $sku_info) { create_product_variation($product_id, $sku_info); } // 获取所有可选项 update_post_meta($product_id, '_product_attributes', array($attribute_name => array( 'name' => $attribute_name, 'value' => '', 'position' => 0, 'is_visible' => 1, 'is_variation' => 1, 'is_taxonomy' => 1 ))); // 保存父产品 $product->save(); } #成功 exit('success'); } else { #失败 exit('fail'); } }变体产品创建函数变体产品对应商品的不同规格，创建方法独立出来//创建变体商品 function create_product_variation( $product_id, $variation_data ){ $product = wc_get_product($product_id); $variation_post = array( 'post_title' => $product->get_title(), 'post_name' => $variation_data['skuName'], 'post_status' => 'publish', 'post_parent' => $product_id, 'post_type' => 'product_variation', 'guid' => $product->get_permalink() ); $variation_id = wp_insert_post( $variation_post ); $variation = new WC_Product_Variation( $variation_id ); //规格属性 $spec_taxonomy = sanitize_title( 'pa_spec'.$product_id );; $spec_term_name = $variation_data['skuName']; $post_spec_term_names = wp_get_post_terms( $product_id, $spec_taxonomy, array('fields' => 'names') ); if( ! in_array( $spec_term_name, $post_spec_term_names ) ){ wp_set_post_terms( $product_id, $spec_term_name, $spec_taxonomy, true ); } //将属性和产品关联 $spec_term_slug = get_term_by('name', $spec_term_name, $spec_taxonomy )->slug; update_post_meta( $variation_id, 'attribute_'.$spec_taxonomy, $spec_term_slug ); //sku if( ! empty( $variation_data['skuId'] ) ) $variation->set_sku( $variation_data['skuId'].date('i:s') ); //价格 if( !empty( $variation_data['price'] ) ){ $variation->set_regular_price($variation_data['price']); $variation->set_sale_price(number_format($variation_data['price']*0.9,2)); } else { $variation->set_price(0); $variation->set_sale_price(0); } //库存 if( ! empty( $variation_data['quantity'] ) ){ $variation->set_stock_quantity( $variation_data['quantity'] ); $variation->set_manage_stock( true ); $variation->set_stock_status( '' ); } else { $variation->set_manage_stock( false ); } $variation->set_weight( '' ); $variation->save(); }完整插件【效率插件】woocommerce之商品批量发布助手
前言开发woocommerce插件开发过程中遇到的问题总结。根据价格获取商品需要根据提供的价格自动匹配商品id和商品名。 public function get_product_id_and_name_by_price($min_price) { $args = array( 'status' => 'publish', 'type' => 'simple', 'meta_query' => array( array( 'key' => '_price', 'value' => $min_price, 'compare' => '>', 'type' => 'numeric' ), ), 'posts_per_page' => 5, ); $query = new WC_Product_Query($args); $products = $query->get_products(); if (empty($products)) { return array(null, 'product-test'); } $product = reset($products); return array($product->get_id(), $product->get_name()); } 注册路由在不同文件内定义，只加载一次 // 公共接口 require_once('functions.php'); if ( ! did_action( 'woocommerce_api_wc_order_pay' ) ) { add_action( 'woocommerce_api_wc_order_pay', 'woo_bbpay_gateway_api_wc_order_pay' ); } if ( ! did_action( 'woocommerce_api_wc_order_result' ) ) { add_action( 'woocommerce_api_wc_order_result', 'woo_bbpay_gateway_api_wc_order_result' ); }
批量创建分类安装插件{message type="error" content="Bulk Category Creator"/}{card-default label="插件" width="80%"}{/card-default}使用{message type="success" content="Dashboard - Product->Bulk Category Creator"/}{card-default label="导入" width="85%"}{/card-default}分类提取cat a.txt | sort |uniq |tr "\n" ","批量导入商品批量导入商品图片利用媒体库导入图片 {card-default label="图片" width="80%"}{/card-default}查看图片文件，插件：Add From Server{card-default label="插件" width="75%"}{/card-default}批量导入商品利用默认功能import即可{card-default label="导入" width="80%"}{/card-default}数据转换处理利用python脚本处理原始数据，生成csv文件#coding=utf-8 # xls 转 csv 脚本 import xlrd import time import random import re from collections import defaultdict import numpy as np import json #数据源文件 R_FILE = './data/Product_List.xls' #起始行 START_ROW = 7 #处理后保存到文件 S_FILE = '../../Downloads/products_%s.csv' % (time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())) S_FILE2 = '../../Downloads/price_rules_%s.csv' % (time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())) #读取表格 class excel_read: def __init__(self, rfile, encoding='utf-8',index=0): self.data=xlrd.open_workbook(rfile) ##获取文本对象 self.table=self.data.sheets()[index] ###根据index获取某个sheet self.rows=self.table.nrows ##获取当前sheet页面的总行数,把每一行数据作为list放到 list def get_data(self): result=[] for i in range(self.rows): col=self.table.row_values(i) ##获取每一行数据 if i == 6: print(col) result.append(col) return result[START_ROW:17] #处理数据 class produce_data: def __init__(self, rawdata): self.rawdata = rawdata def _get_ns(self): ''' 生成随机数ns(0s至1s之间) ''' return int(random.random()*1000000000) def produce(self): ''' 数据处理主函数 ''' #表头信息 head_str ='' + \ 'Type,' + \ 'SKU,' + \ 'Name,' + \ 'Published,' + \ '"Is featured?",' + \ '"Visibility in catalog",' + \ '"Short description",' + \ 'Description,' + \ '"In stock?",' + \ '"Sale price",' + \ '"Regular price",' + \ 'Categories,' + \ 'Tags,' + \ 'Images' #价格列表 prices = [] #后面一定要有空格 body_str = '' for item in self.rawdata: print(item) #图片链接 img_url='https://4ilogo.com/wp-content/uploads/2022/12/{}.jpg'.format(item[1]) #构建条目 body_str += '{},{},"{}",{},{},{},"{}","{}",{},{},{},"{}","{}",{}\n'.format( 'simple', # Type item[1], # SKU item[2], # Name 1, # Published 0, # Is featured 'visible', # Visibility in catalog item[11], # Short description item[10], # Description 1, # is stock? item[29], # Sale price item[29], # Regular price item[6], # Categories item[6], # Tags img_url # Images ) #价格规则 prices.append({ "type": "single_item", "rule_type": "common", "filters": [ { "qty": 1, "type": "product_sku", "method": "in_list", "value": [ item[1] ], "product_exclude": { "on_wc_sale": "", "already_affected": "", "backorder": "", "values": [] } } ], "title": item[1], "priority": "", "enabled": "on", "sortable_blocks_priority": [ "roles", "bulk-adjustments" ], "additional": { "conditions_relationship": "and", "is_replace": "", "replace_name": "", "is_replace_free_products_with_discount": "", "free_products_replace_name": "", "is_replace_auto_add_products_with_discount": "", "auto_add_products_replace_name": "", "sortable_apply_mode": "consistently" }, "conditions": [], "cart_adjustments": [], "limits": [], "bulk_adjustments": { "type": "bulk", "qty_based": "not", "discount_type": "price__fixed", "ranges": [ { "from": int(item[23]), "to": int(item[24]), "value": item[29] }, { "from": int(item[24] + 1), "to": int(item[25]), "value": item[30] }, { "from": int(item[25] + 1), "to": int(item[26]), "value": item[31] }, { "from": int(item[26] + 1), "to": int(item[27]), "value": item[32] }, { "from": int(item[27] + 1), "to": int(item[28]), "value": item[33] }, { "from": int(item[28] + 1), "to": "", "value": item[34] } ], "table_message": "" }, "role_discounts": [], "get_products": { "repeat": "-1", "repeat_subtotal": "", "max_amount_for_gifts": "null" }, "auto_add_products": { "repeat": "-1", "repeat_subtotal": "" }, "options": { "apply_to": "expensive", "repeat": -1 }, "advertising": { "discount_message": "", "discount_message_cart_item": "", "long_discount_message": "", "sale_badge": "" }, "version": "4.2.0" }) pro_str = head_str + '\n' + body_str #返回字符串 return pro_str, prices #主函数 if __name__ == '__main__': print('正在读取数据... %s' % (R_FILE)) datalist = excel_read(R_FILE).get_data() print('正在处理数据...') product_str, price_arr = produce_data(datalist).produce() #将结果写入文件 print('正在保存商品信息到 %s' % (S_FILE)) with open(S_FILE, 'w') as fs: fs.write(product_str) print('正在保存价格规则到 %s' % (S_FILE2)) with open(S_FILE2, 'w') as fs: fs.write(json.dumps(price_arr, ensure_ascii=False)) print('完成') exit()批量设置批发价格插件: Advanced Dynamic Pricing for WooCommerce{card-default label="价格规则" width="90%"}{/card-default}{card-default label="批量导入功能" width="85%"}{/card-default}
前言woocommerce的订单详情页展示的信息有限。改造一下代码，以展示更多的信息。代码{message type="success" content="修改主题的functions.php文件，在底部添加"/}订单详情页添加本地订单号和平台订单号{card-default label="详情" width="80%"}{/card-default}// 路径：wp-content/themes/razzi/functions.php // 在管理员后台订单详细页面也显示一下 add_action( 'init', 'twentytwentyfour_pattern_categories' ); // 在管理员后台订单详细页面也显示一下 add_action( 'woocommerce_admin_order_data_after_order_details', 'brain_display_order_data_in_admin' ); function brain_display_order_data_in_admin( $order ){ ?> <?php _e( 'Extra Order Details', 'woocommerce' ); ?> <?php global $wpdb; $order_extra_info = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}qeaepay_data WHERE order_id = '".$order->get_id()."'"); echo ' ' . __( '本地订单号' ) . ': '; echo ' ' . $order_extra_info->mref . ' '; echo ' ' . __( '通道订单号' ) . ': ' . $order_extra_info->sref . ' '; ?> <?php } 修改副标题信息，所有支付方式都类似PayPal方式展示{card-default label="效果" width="80%"}{/card-default}//wp-content/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php //194行 if ( $payment_method ) { ... }订单列表页{card-default label="列表" width="80%"}{/card-default}// 路径：wp-content/themes/razzi/functions.php // 添加2列自定义标题 ，放在订单列的后面 add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 20 ); function custom_shop_order_column($columns){ $reordered_columns = array(); foreach( $columns as $key => $column){ $reordered_columns[$key] = $column; if( $key == 'order_number' ){ $reordered_columns['custom_column1'] = __( '本地订单号','theme_domain'); $reordered_columns['custom_column2'] = __( '上游订单号','theme_domain'); } } return $reordered_columns; } //为列指定元数据 add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 20, 2 ); function custom_orders_list_column_content( $column, $post_id ){ global $wpdb; $order_extra_info = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}superxpay_rapay_data WHERE orderid = '".$post_id."'"); switch ( $column ){ case 'custom_column1' : if(!empty($order_extra_info)) echo $order_extra_info->ref; else echo '.'; break; case 'custom_column2' : if(!empty($order_extra_info)) echo $order_extra_info->ordercode; else echo '.'; break; } }