Add WeChat Pay to WordPress with Omnipay WechatPay: JS SDK Public Account Payments

WeChat Pay quickly became one of the most common mobile payment methods in China. If you are building a site that is meant to run inside WeChat, the usual native QR code flow is not a good fit. In that case you should use the WeChat JS SDK payment flow instead.

This approach still relies on Omnipay WechatPay, but it switches from the desktop-style QR code interface to the JavaScript payment API that opens the WeChat payment dialog directly inside the client.

Step 1: Install the required packages

The payment package is still lokielse/omnipay-wechatpay. In this example the project also uses thefold/wordpress-dispatcher for custom routes and vlucas/valitron for form validation.

{
  "require": {
    "omnipay/omnipay": "~2.0",
    "lokielse/omnipay-wechatpay": "^1.0",
    "thefold/wordpress-dispatcher": "^1.0",
    "vlucas/valitron": "^1.2"
  }
}

After running composer install, load Composer’s autoloader in your theme or plugin:

require_once get_template_directory() . '/vendor/autoload.php';

Front-end: initialize the WeChat JS SDK and trigger payment

WeChat’s official jssdk.php file can generate the signature package required by the JS SDK. Include it on the page where payment happens, then create the sign package on the server side.

require_once get_template_directory() . '/inc/jssdk.php';
$jssdk = new JSSDK('your-app-id', 'your-app-secret');
$signPackage = $jssdk->GetSignPackage();

Make sure the page loads the WeChat JavaScript SDK, then use wx.config and wx.ready to prepare the client-side environment. When the user clicks the payment button, send an Ajax request to your server, create the unified order, and pass the returned parameters into wx.chooseWXPay.

jQuery(function ($) {
  wx.config({
    debug: false,
    appId: signPackage.appId,
    timestamp: signPackage.timestamp,
    nonceStr: signPackage.nonceStr,
    signature: signPackage.signature,
    jsApiList: ['chooseWXPay']
  });

  wx.ready(function () {
    $('#pay-button').on('click', function () {
      $.post(ajaxurl, { action: 'create_wechat_order' }, function (response) {
        wx.chooseWXPay({
          timestamp: response.timestamp,
          nonceStr: response.nonceStr,
          package: response.package,
          signType: response.signType,
          paySign: response.paySign
        });
      }, 'json');
    });
  });
});

If the payment window flashes and disappears

If the WeChat payment window appears for a moment and then closes immediately, check these items carefully:

  • The JS SDK was not initialized correctly. Recheck wx.config and wx.ready.
  • Your Ajax response contains invalid payment data.
  • The current domain was not added to the trusted JS security domain in the WeChat management console.

Back-end: validate data and return order parameters

On the server side you receive the Ajax request, validate the submitted data, create the WeChat order, and save the order record locally so it can be queried later or matched during asynchronous callbacks.

function get_wechat_gateway() {
    $gateway = Omnipay::create('WechatPay_Js');
    $gateway->setAppId('your-app-id');
    $gateway->setMchId('your-merchant-id');
    $gateway->setApiKey('your-api-key');
    $gateway->setNotifyUrl(home_url('/wechat/notify'));
    return $gateway;
}

function create_wechat_order() {
    $gateway = get_wechat_gateway();

    $response = $gateway->purchase([
        'body' => 'Order title',
        'out_trade_no' => uniqid('wx_'),
        'total_fee' => 100,
        'fee_type' => 'CNY',
        'client_ip' => $_SERVER['REMOTE_ADDR'],
        'openid' => $openid,
    ])->send();

    if ($response->isSuccessful()) {
        wp_send_json($response->getJsOrderData());
    }

    wp_send_json_error($response->getMessage());
}

Handle successful payment notifications

After payment succeeds, WeChat sends an asynchronous notification to the callback URL you provided. That callback is where you should mark the order as paid, complete a recharge, or trigger any other business logic.

The key point is to treat the callback as the final source of truth. Do not rely only on the front-end success state, because the user may close the page or the client may fail to return cleanly after payment.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *