افزونه وردپرس - ووكامرس
افزونه پرداخت براي فروشگاه ووكامرس
دانلود ثبت شده
101
آخرین بروزرسانی
2026-09-25
حجم بسته
339.6 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
در این صفحه بسته های آماده برای اتصال به سرویس پرداخت، افزونه های کمکی و مثال های اجرایی را مثل یک ریپازیتوری مرور می کنید: فایل ها را می بینید، README را می خوانید و کل بسته را با یک دانلود می گیرید.
CONTROLLED RELEASE
انتشار کنترل شده از پنل رسمی
هر بسته از مسیر مدیریتی رسمی پی اکسا منتشر می شود و قبل از دانلود، اطلاعات کلیدی آن به صورت شفاف نمایش داده می شود.
PRE-DOWNLOAD VISIBILITY
شفافیت محتوا پیش از دریافت
پیش نمایش README، مرور ساختار فایل و نمایش متادیتای بسته کمک می کند قبل از دانلود، ارزیابی دقیق تری از محتوا داشته باشید.
TRUST PROFILE
نمای رسمی تر برای انتخاب ابزار
صفحه بر پایه شفافیت انتشار، نمایش منبع README، تاریخ بروزرسانی و آمار دانلود چیده شده تا حس ارزیابی حرفه ای تری منتقل کند.
مرجع حقوقی و هویتی کنار دسترس
ساختار صفحه طوری چیده شده که اطلاعات انتشار، محتوای فایل ها و جزئیات هر بسته بدون شلوغی اضافه در دسترس باشند.
افزونه پرداخت براي فروشگاه ووكامرس
دانلود ثبت شده
101
آخرین بروزرسانی
2026-09-25
حجم بسته
339.6 KB
منتشرکننده
مدیر ارشد سامانه
وضعیت نمایش
عمومی و فعال
پوشه جاری را انتخاب کنید یا برای فایل های متنی پیش نمایش بگیرید.
| نام | نوع | اندازه |
|---|---|---|
| بازگشت به پوشه قبل | پوشه | - |
| class-payexa-api.php | قابل پیش نمایش | 17.3 KB |
| class-payexa-blocks-support.php | قابل پیش نمایش | 1.1 KB |
| class-payexa-gateway.php | قابل پیش نمایش | 5.9 KB |
| class-payexa-plugin.php | قابل پیش نمایش | 18.8 KB |
payexa-gateway/includes/class-payexa-api.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Payexa_API {
const SANDBOX_BASE_URL = 'https://sandbox.pexn.ir';
const PRODUCTION_BASE_URL = 'https://pay.pexn.ir';
const SANDBOX_TOKEN = 'PAYEXA';
protected $logger;
public function __construct() {
$this->logger = function_exists( 'wc_get_logger' ) ? wc_get_logger() : null;
}
public function request_payment( WC_Order $order, array $settings ) {
$endpoint = $this->build_url( '/v1/payment/request', $settings );
$order_ref = $this->build_order_reference( $order, $settings );
$payload = array(
'amount' => $this->normalize_amount( $order->get_total(), $settings ),
'callback_url' => add_query_arg(
array(
'order_id' => $order->get_id(),
'key' => $order->get_order_key(),
),
$this->get_callback_url()
),
'meta' => array(
'order_ref' => $order_ref,
),
);
$response = $this->send_json_request( $endpoint, $payload, $settings, array( 201 ) );
if ( is_wp_error( $response ) ) {
return $response;
}
$data = $response['body'];
$authority = $data['authority'] ?? null;
$request_order = $data['order_id'] ?? null;
$amount_unique = $data['amount_unique'] ?? null;
$payment_url = $authority ? $this->build_payment_redirect_url( $authority, $settings ) : null;
if ( ! $authority || ! $request_order || null === $amount_unique || ! $payment_url ) {
$this->log( 'invalid_request_response', array( 'response' => $data ) );
return new WP_Error( 'payexa_invalid_response', 'پاسخ نامعتبر از سرویس پی اکسا دریافت شد.' );
}
return array(
'order_ref' => sanitize_text_field( $order_ref ),
'authority' => sanitize_text_field( $authority ),
'verify_token' => $this->normalize_verify_token( $amount_unique ),
'request_order_id' => sanitize_text_field( $request_order ),
'gateway_order_id' => sanitize_text_field( $request_order ),
'payment_url' => esc_url_raw( $payment_url ),
'raw' => $data,
);
}
public function verify_payment( WC_Order $order, array $settings ) {
$endpoint = $this->build_url( '/v1/payment/verify', $settings );
$request_order_id = $this->get_stored_request_order_id( $order );
$verify_token = $this->get_stored_verify_token( $order );
if ( ! $request_order_id ) {
return new WP_Error( 'payexa_missing_gateway_order', 'شناسه سفارش Payexa برای وریفای در دسترس نیست.' );
}
if ( ! $verify_token ) {
return new WP_Error( 'payexa_missing_verify_token', 'توکن وریفای Payexa برای استعلام در دسترس نیست.' );
}
$payload = array(
'order_id' => sanitize_text_field( $request_order_id ),
'token' => $verify_token,
);
$this->log( 'verify_request', array( 'payload' => $payload, 'order_id' => $order->get_id() ) );
$response = $this->send_json_request( $endpoint, $payload, $settings, array( 200, 201, 400, 401, 402, 403, 404, 409, 422, 429, 500 ), false );
if ( is_wp_error( $response ) ) {
return $response;
}
$code = (int) $response['code'];
$data = $response['body'];
$status = $this->normalize_verify_status( $code, $data );
$tracking_code = $this->extract_tracking_code( $data, $order );
if ( 'pending' === $status ) {
return array(
'status' => 'pending',
'tracking_code' => $tracking_code,
'verification_code' => $code,
'request_order_id' => sanitize_text_field( $request_order_id ),
'raw' => $data,
);
}
if ( 'already_verified' === $status ) {
return array(
'status' => 'already_verified',
'tracking_code' => $tracking_code,
'verification_code' => $code,
'request_order_id' => sanitize_text_field( $request_order_id ),
'raw' => $data,
);
}
if ( 'success' !== $status ) {
$message = $this->map_api_error_message( $code, $data, 'تایید تراکنش توسط پی اکسا انجام نشد.' );
return new WP_Error( 'payexa_verify_failed', $message, array( 'code' => $code, 'body' => $data ) );
}
return array(
'status' => 'success',
'tracking_code' => $tracking_code,
'verification_code' => $code,
'merchant_verified' => true,
'request_order_id' => sanitize_text_field( $request_order_id ),
'merchant_verified_at' => sanitize_text_field( (string) $this->extract_response_value( $data, array( 'merchant_verified_at' ), '' ) ),
'raw' => $data,
);
}
public function test_connection( array $settings ) {
$token = $this->get_token( $settings );
if ( 'sandbox' === ( $settings['environment'] ?? 'production' ) ) {
return array(
'code' => 200,
'message' => 'محیط سندباکس فعال است. کلید API در حالت سندباکس نیاز به تایید ندارد.',
'is_token_valid' => true,
'is_server_alive' => true,
'connected' => true,
'merchant_name' => 'Sandbox',
'merchant_status' => 'active',
'endpoint' => $this->build_url( '/v1/payment/request', $settings ),
);
}
$endpoint = $this->build_url( '/v1/merchant/api-key/validate', $settings );
if ( '' === $token ) {
return new WP_Error( 'payexa_missing_api_key', 'برای استفاده از محیط عملیاتی، ابتدا کلید API را وارد کنید.' );
}
$args = array(
'method' => 'GET',
'timeout' => 30,
'headers' => array(
'Accept' => 'application/json',
'X-API-KEY' => $token,
),
);
$this->log( 'connection_test_request', array( 'url' => $endpoint ) );
$result = $this->do_http_request( 'GET', $endpoint, $args );
if ( is_wp_error( $result ) ) {
$this->log( 'connection_test_error', array( 'message' => $result->get_error_message() ) );
return new WP_Error( 'payexa_network_error', 'ارتباط با درگاه پی اکسا برقرار نشد. لطفا دوباره تلاش کنید.' );
}
$code = $result['code'];
$body = json_decode( $result['raw_body'], true );
if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $body ) ) {
$this->log( 'connection_test_json_error', array( 'code' => $code, 'body' => $result['raw_body'] ) );
return new WP_Error( 'payexa_invalid_json', 'پاسخ دریافتی از درگاه قابل پردازش نبود.' );
}
$this->log( 'connection_test_response', array( 'code' => $code, 'body' => $body ) );
$connected = ! empty( $body['connected'] );
$status_is_valid = isset( $body['status'] ) ? (bool) $body['status'] : false;
$message = $this->map_api_error_message( $code, $body, 'پاسخ نامشخص از سرویس پی اکسا دریافت شد.' );
$merchant_name = sanitize_text_field( (string) ( $body['merchant_name'] ?? '' ) );
$merchant_status = sanitize_text_field( (string) ( $body['merchant_status'] ?? '' ) );
return array(
'code' => $code,
'message' => $message,
'is_token_valid' => 200 === $code && $connected && $status_is_valid,
'is_server_alive' => true,
'connected' => $connected,
'merchant_name' => $merchant_name,
'merchant_status' => $merchant_status,
'endpoint' => $endpoint,
);
}
protected function send_json_request( $url, array $payload, array $settings, array $accepted_codes = array( 200 ), $return_error_on_http = true ) {
$args = array(
'method' => 'POST',
'timeout' => 30,
'headers' => array(
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'X-API-KEY' => $this->get_token( $settings ),
),
'body' => wp_json_encode( $payload ),
);
$this->log( 'request', array( 'url' => $url, 'payload' => $payload ) );
$result = $this->do_http_request( 'POST', $url, $args );
if ( is_wp_error( $result ) ) {
$this->log( 'network_error', array( 'message' => $result->get_error_message() ) );
return new WP_Error( 'payexa_network_error', 'ارتباط با درگاه پی اکسا برقرار نشد. لطفا دوباره تلاش کنید.' );
}
$code = $result['code'];
$body = json_decode( $result['raw_body'], true );
if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $body ) ) {
$this->log( 'json_error', array( 'code' => $code, 'body' => wp_remote_retrieve_body( $response ) ) );
return new WP_Error( 'payexa_invalid_json', 'پاسخ دریافتی از درگاه قابل پردازش نبود.' );
}
$this->log( 'response', array( 'code' => $code, 'body' => $body ) );
if ( ! in_array( $code, $accepted_codes, true ) && $return_error_on_http ) {
$message = $this->map_api_error_message( $code, $body, 'درخواست به پی اکسا با خطا مواجه شد.' );
return new WP_Error( 'payexa_http_error', sanitize_text_field( $message ) );
}
if ( isset( $body['success'] ) && false === $body['success'] ) {
$message = $body['message'] ?? 'درگاه پی اکسا درخواست را رد کرد.';
return new WP_Error( 'payexa_api_rejected', sanitize_text_field( $message ) );
}
return array(
'code' => $code,
'body' => $body,
);
}
protected function build_order_reference( WC_Order $order, array $settings ) {
$merchant_fingerprint = substr( hash( 'sha256', strtoupper( $this->get_token( $settings ) ) ), 0, 10 );
$microtime_part = (string) (int) round( microtime( true ) * 1000000 );
$random_part = strtoupper( wp_generate_password( 8, false, false ) );
return sprintf( 'PX-%s-%s-%s-%s', $merchant_fingerprint, $order->get_id(), $microtime_part, $random_part );
}
protected function build_payment_redirect_url( $authority, array $settings ) {
return untrailingslashit( $this->get_base_url( $settings ) ) . '/startPay?authority=' . rawurlencode( $authority );
}
protected function get_callback_url() {
if ( function_exists( 'WC' ) && WC() && method_exists( WC(), 'api_request_url' ) ) {
return WC()->api_request_url( 'payexa_callback' );
}
return add_query_arg( array( 'wc-api' => 'payexa_callback' ), home_url( '/' ) );
}
protected function build_url( $path, array $settings ) {
return untrailingslashit( $this->get_base_url( $settings ) ) . $path;
}
protected function get_base_url( array $settings ) {
return $this->is_sandbox_mode( $settings ) ? self::SANDBOX_BASE_URL : self::PRODUCTION_BASE_URL;
}
protected function get_token( array $settings ) {
if ( $this->is_sandbox_mode( $settings ) ) {
return self::SANDBOX_TOKEN;
}
return isset( $settings['api_key'] ) ? trim( (string) $settings['api_key'] ) : '';
}
protected function is_sandbox_mode( array $settings ) {
if ( 'sandbox' === sanitize_key( (string) ( $settings['environment'] ?? '' ) ) ) {
return true;
}
return $this->is_sandbox_token( $settings['api_key'] ?? '' );
}
protected function is_sandbox_token( $value ) {
return 'PAYEXA' === strtoupper( trim( (string) $value ) );
}
protected function normalize_amount( $amount, array $settings = array() ) {
$value = (float) $amount;
$currency = $settings['currency'] ?? 'auto';
if ( 'IRT' === $currency ) {
$value *= 10;
} elseif ( 'auto' === $currency ) {
$wc_currency = function_exists( 'get_woocommerce_currency' ) ? strtoupper( get_woocommerce_currency() ) : '';
if ( in_array( $wc_currency, array( 'IRT', 'TOMAN', 'TMN' ), true ) ) {
$value *= 10;
}
}
return (int) round( $value );
}
protected function normalize_verify_token( $value ) {
$value = trim( (string) $value );
if ( is_numeric( $value ) ) {
$value = rtrim( rtrim( number_format( (float) $value, 4, '.', '' ), '0' ), '.' );
}
return sanitize_text_field( $value );
}
protected function normalize_verify_status( $code, array $body ) {
$status = strtoupper( (string) $this->extract_response_value( $body, array( 'status' ), '' ) );
$merchant_verified = $this->extract_response_value( $body, array( 'merchant_verified' ), null );
if ( 201 === (int) $code ) {
return 'already_verified';
}
if ( 200 === (int) $code && 'SUCCESS' === $status && $this->is_truthy_value( $merchant_verified ) ) {
return 'success';
}
return 'failed';
}
protected function get_stored_request_order_id( WC_Order $order ) {
$request_order_id = $order->get_meta( '_payexa_request_order_id', true );
if ( ! $request_order_id ) {
$request_order_id = $order->get_meta( '_payexa_gateway_order_id', true );
}
return sanitize_text_field( (string) $request_order_id );
}
protected function get_stored_verify_token( WC_Order $order ) {
$verify_token = $order->get_meta( '_payexa_verify_token', true );
if ( ! $verify_token ) {
$verify_token = $order->get_meta( '_payexa_amount_unique', true );
}
return $this->normalize_verify_token( $verify_token );
}
protected function extract_tracking_code( array $body, WC_Order $order ) {
$tracking_code = $this->extract_response_value(
$body,
array( 'tracking_code', 'trackingCode', 'reference_id', 'referenceId', 'ref_id', 'refId', 'transaction_id', 'transactionId' ),
''
);
if ( '' === (string) $tracking_code ) {
$tracking_code = (string) $order->get_meta( '_payexa_authority', true );
}
if ( '' === (string) $tracking_code ) {
$tracking_code = (string) $order->get_meta( '_payexa_verify_token', true );
}
return sanitize_text_field( (string) $tracking_code );
}
protected function extract_response_value( array $body, array $keys, $default = '' ) {
$sources = array( $body );
foreach ( array( 'data', 'result', 'payment', 'transaction' ) as $container_key ) {
if ( isset( $body[ $container_key ] ) && is_array( $body[ $container_key ] ) ) {
$sources[] = $body[ $container_key ];
}
}
foreach ( $sources as $source ) {
foreach ( $keys as $key ) {
if ( isset( $source[ $key ] ) && '' !== $source[ $key ] && null !== $source[ $key ] ) {
return $source[ $key ];
}
}
}
return $default;
}
protected function is_truthy_value( $value ) {
if ( true === $value || 1 === $value || '1' === $value ) {
return true;
}
return in_array( strtolower( trim( (string) $value ) ), array( 'true', 'yes', 'ok', 'success' ), true );
}
protected function map_api_error_message( $code, array $body, $default_message ) {
$message = $body['message'] ?? $body['error'] ?? '';
if ( $message ) {
return sanitize_text_field( (string) $message );
}
$messages = array(
400 => 'درخواست ارسالی به پی اکسا نامعتبر است.',
401 => 'کلید API پی اکسا نامعتبر است یا ارسال نشده است.',
402 => 'موجودی کیف پول پذیرنده برای کارمزد کافی نیست.',
403 => 'کلید API معتبر نیست یا پذیرنده فعال نیست.',
404 => 'تراکنش یا سفارش در پی اکسا پیدا نشد.',
409 => 'تراکنش هنوز نهایی نشده است و باید کمی بعد دوباره بررسی شود.',
422 => 'اطلاعات ارسالی به پی اکسا از نظر اعتبارسنجی صحیح نیست.',
429 => 'تعداد درخواست ها بیش از حد مجاز است. کمی بعد دوباره تلاش کنید.',
500 => 'خطای داخلی در سرویس پی اکسا رخ داده است.',
503 => 'سرویس پی اکسا موقتا در دسترس نیست.',
);
return $messages[ $code ] ?? $default_message;
}
protected function do_http_request( $method, $url, array $args ) {
if ( 'POST' === $method ) {
$response = wp_remote_post( $url, $args );
} else {
$response = wp_remote_get( $url, $args );
}
if ( ! is_wp_error( $response ) ) {
return array(
'code' => (int) wp_remote_retrieve_response_code( $response ),
'raw_body' => wp_remote_retrieve_body( $response ),
);
}
if ( stripos( $response->get_error_message(), 'blocked' ) !== false && function_exists( 'curl_init' ) ) {
$this->log( 'curl_fallback_attempt', array( 'reason' => $response->get_error_message() ) );
return $this->native_curl_request( $method, $url, $args );
}
return $response;
}
protected function native_curl_request( $method, $url, array $args ) {
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_TIMEOUT, $args['timeout'] ?? 30 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
$headers = array();
foreach ( ( $args['headers'] ?? array() ) as $key => $value ) {
$headers[] = $key . ': ' . $value;
}
if ( $headers ) {
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
}
if ( 'POST' === $method ) {
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $args['body'] ?? '' );
}
$raw_body = curl_exec( $ch );
$curl_error = curl_error( $ch );
$code = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE );
curl_close( $ch );
if ( false === $raw_body ) {
$this->log( 'curl_fallback_error', array( 'message' => $curl_error ) );
return new WP_Error( 'payexa_network_error', 'ارتباط با درگاه پی اکسا برقرار نشد. لطفا دوباره تلاش کنید.' );
}
$this->log( 'curl_fallback_success', array( 'code' => $code ) );
return array(
'code' => $code,
'raw_body' => $raw_body,
);
}
protected function log( $message, array $context = array() ) {
if ( $this->logger ) {
$this->logger->info( $message . ' ' . wp_json_encode( $context, JSON_UNESCAPED_UNICODE ), array( 'source' => 'payexa-gateway' ) );
}
}
}
منبع: readme.txt
=== Payexa Gateway for WooCommerce | درگاه پرداخت پی اکسا برای ووکامرس === Contributors: payexa Tags: payment, gateway, payexa, pexn, woocommerce, iran payment, درگاه پرداخت, پیاکسا, پرداخت آنلاین, ووکامرس Requires at least: 6.4 Tested up to: 6.8 Requires PHP: 7.4 Stable tag: 1.0.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html WC requires at least: 8.0 WC tested up to: 9.0
افزونه حرفه ای درگاه پرداخت Payexa برای WooCommerce با رابط فارسی RTL، تایید تراکنش، حالت سندباکس و بازگشت استاندارد به صفحات خود ووکامرس. Professional Payexa payment gateway for WooCommerce with Persian RTL UX, PAYEXA sandbox token support, transaction verification, and standard WooCommerce order flow.
== Description ==
Payexa Gateway for WooCommerce یک افزونه حرفه ای برای اتصال فروشگاه وردپرسی شما به درگاه پرداخت پی اکسا است. این افزونه برای فروشگاه های فارسی زبان، کسب وکارهای ایرانی و توسعه دهندگانی طراحی شده است که به یک درگاه پرداخت WooCommerce سبک، پایدار، امن و آماده انتشار نیاز دارند.
Payexa Gateway for WooCommerce provides a production-grade payment gateway integration for merchants who need a reliable Payexa, PEXN, and Iran payment solution inside WooCommerce. The plugin includes sandbox support, callback verification, structured logging, RTL Persian UI, and a clean checkout experience.
Features and SEO keywords:
Why this WooCommerce Payexa plugin matters:
Plugin capabilities:
== Third-Party Services ==
This plugin connects to the external Payexa payment service to create and verify payment transactions.
It sends the following data to Payexa when a customer starts payment:
It sends the following data to Payexa when verifying a payment:
The service endpoints used by the plugin are:
Merchant API keys are stored in WordPress and sent server-to-server in the X-API-KEY header.
Please review the provider terms and policies before using the service:
== Installation ==
== Frequently Asked Questions ==
= آیا افزونه از سندباکس پشتیبانی می کند؟ = بله. برای استفاده از سندباکس کافی است در فیلد API Key مقدار PAYEXA را وارد کنید تا افزونه به صورت خودکار از آدرس sandbox و توکن ثابت PAYEXA استفاده کند.
= برای محیط واقعی چه چیزی لازم است؟ = باید در pexn.ir ثبت نام کنید و API token اختصاصی خود را در تنظیمات افزونه وارد کنید.
= آیا این افزونه برای ووکامرس فارسی مناسب است؟ = بله. رابط مدیریت، پیام های کاربری و چیدمان checkout به صورت فارسی و RTL طراحی شده است.
= آیا لاگ ثبت می شود؟ = بله. این افزونه از WooCommerce Logger برای ثبت درخواست، پاسخ و خطاهای ارتباطی استفاده می کند.
= هدرهای رسمی API چگونه ارسال می شوند؟ = افزونه درخواست های سروری Payexa را با هدرهای Content-Type: application/json و X-API-KEY ارسال می کند. کلید API فقط در سمت سرور وردپرس نگهداری می شود.
= سفارش دقیقا چه زمانی موفق می شود؟ = فقط وقتی verify پی اکسا با HTTP 200 و status برابر SUCCESS برگردد، سفارش نهایی می شود. اگر verify کد 201 برگرداند، یعنی قبلا تایید شده و افزونه از ثبت موفقیت تکراری جلوگیری می کند.
== Screenshots ==
== Changelog ==
= 1.0.0 = * انتشار اولیه افزونه درگاه پرداخت Payexa برای WooCommerce * افزودن request، verify و callback حرفه ای * افزودن پنل تنظیمات فارسی RTL * استفاده از بازگشت استاندارد WooCommerce برای حالت موفق و ناموفق * افزودن readme دو زبانه با تمرکز بر سئو کلمات کلیدی payment gateway, Payexa, PEXN, WooCommerce, درگاه پرداخت
== Upgrade Notice ==
= 1.0.0 = اولین نسخه پایدار افزونه Payexa Gateway for WooCommerce منتشر شد.
من دستیار پی اکسا هستم، شما را در تمام مسیر راهنمایی میکنم و اگر به من نیازی ندارید با ۲ بار کلیک خاموش میشوم.