I am trying to connect to an api using the code below, so when the customer clicks on the "place order" button on the Woocommerce checkout page, I am getting a "please try again" error:
var amount = <?php global $woocommerce; print WC()->cart->total; ?>;
var merchantOrderId = '<?php echo print time(); ?>';
var apiKey = 'm85BXXLpf_icrSvqbElR11xquEgmKZ8wfeRb2ly3-G7pIwCKDuytgplB7AQGi-5t';
renderMMoneyPaymentButton(amount, merchantOrderId, apiKey);
I am trying to pass this information to the api via this function but I am not getting a successful connection.
public function process_payment( $order_id ) {
global $woocommerce;
// we need it to get any order detailes
$order = new WC_Order($order_id);
/*
* Array with parameters for API interaction
*/
$args = array(
'amount' => '<?php global $woocommerce; print WC()->cart->total; ?>',
'merchant_order_id' => '<?php print time(); ?>',
'api_Key' => 'm85BXXLpf_icrSvqbElR11xquEgmKZ8wfeRb2ly3-G7pIwCKDuytgplB7AQGi-5t',
'currency' => 'BBD',
);
/*
* Your API interaction could be built with wp_remote_post()
*/
$response = wp_remote_post( 'https://api.mmoneybb.com/merchant/js/mmoney-payment.js', $args );
if( !is_wp_error( $response ) ) {
$body = json_decode( $response['body'], true );
// it could be different depending on your payment processor
if ( $body ['$response'] == 'APPROVED') {
// we received the payment
$order->payment_complete();
$order->reduce_order_stock();
// some notes to customer (replace true with false to make it private)
$order->add_order_note( 'Thanks for your payment!!!!', true );
// Empty cart
$woocommerce->cart->empty_cart();
// Redirect to the thank you page
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
} else {
wc_add_notice( 'Please try again.', 'error' );
return;
}
} else {
wc_add_notice( 'Connection error.', 'error' );
return;
}
}
let me know what i am doing wrong much appreciated also this is the other script as well
function renderMMoneyPaymentButton(amount, merchantOrderId, apiKey) {
let paymentParams = {
amount: amount,
api_key: apiKey,
currency: 'BBD',
merchant_order_id: merchantOrderId,
onCancel: function () { console.log('Modal closed'); },
onError: function(error) { console.log('Error', error); },
onPaid: function (invoice) { console.log('Payment complete', invoice); }
};
// "mMoney" window global provided by sourcing mmoney-payment.js script.
// Attach the button to the empty element.
mMoney.payment.button.render(paymentParams, '#mmoney-payment-button');
}
1) In your first snippet code you are using javascript and you need to get the order Id and then the order total… You can only get the Order ID after the order is placed…
There is an answer example here.
2) Your 2nd public function involves only PHP… There are some errors and mistakes in this code. Try the following revisited code instead:
public function process_payment( $order_id ) {
// Get The WC_Order Object instance
$order = wc_get_order( $order_id );
/*
* Array with parameters for API interaction
*/
$args = array(
'amount' => $order->get_total(),
'merchant_order_id' => $order_id,
'api_Key' => 'm85BXXLpf_icrSvqbElR11xquEgmKZ8wfeRb2ly3-G7pIwCKDuytgplB7AQGi-5t',
'currency' => $order->get_currency(),
);
/*
* Your API interaction could be built with wp_remote_post()
*/
$response = wp_remote_post( 'https://api.mmoneybb.com/merchant/js/mmoney-payment.js', $args );
if( !is_wp_error( $response ) ) {
$body = json_decode( $response['body'], true );
// it could be different depending on your payment processor
if ( $body ['$response'] == 'APPROVED') {
// we received the payment
$order->payment_complete();
$order->reduce_order_stock();
// some notes to customer (replace true with false to make it private)
$order->add_order_note( 'Thanks for your payment!!!!', true );
// Empty cart
$woocommerce->cart->empty_cart();
// Redirect to the thank you page
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
} else {
wc_add_notice( 'Please try again.', 'error' );
return;
}
} else {
wc_add_notice( 'Connection error.', 'error' );
return;
}
}
It should better work.
Related
Please accept my apology in advance if my question is long.
I am using a payment gateway of woocommerce.
When click on checkout it goes to an external link. Then there We have button to click and Then It goes to another link which make it enable to pay via cards.
Now What I want to do is that.
I want to minimize some step.
1- If possible I want to bypass detail page which appears after click on Checkout button.
2- Is this possible to hide amount on detail page. As my website currecny is different and this payment gateway the show in different.
3- If above 1,2 not possible. Can simply put external pages in a iframe.
So if user click on check out. It should show a ifram on new page current page with redirected link.
Below code is from gateway plugin.
<?php
add_action( 'plugins_loaded', 'init_pp_woo_gateway');
function mib_ppbycp_settings( $links ) {
$settings_link = 'Setup';
array_push( $links, $settings_link );
return $links;
}
$plugin = plugin_basename( __FILE__ );
add_filter( "plugin_action_links_$plugin", 'mib_ppbycp_settings' );
function init_pp_woo_gateway(){
if ( ! class_exists( 'WC_Payment_Gateway' ) ) return;
class WC_Gateway_MIB_PayPro extends WC_Payment_Gateway {
// Logging
public static $log_enabled = false;
public static $log = false;
var $merchant_id;
var $merchant_password;
var $test_mode;
var $plugin_url;
var $timeout;
var $checkout_url;
var $api_url;
var $timeout_in_days;
public function __construct(){
global $woocommerce;
$this -> plugin_url = WP_PLUGIN_URL . DIRECTORY_SEPARATOR . 'woocommerce-paypro-payment';
$this->id = 'mibwoo_pp';
$this->has_fields = false;
$this->checkout_url = 'https://marketplace.paypro.com.pk/';
$this->icon = 'https://thebalmainworld.com/wp-content/uploads/2020/10/Credit-Card-Icons-copy-1.png';
$this->method_title = 'Paypro';
$this->method_description = 'Pay via Debit/Credit card.';
$this->title = "Paypro";
$this->description = "Pay via Debit/Credit card.";
$this->merchant_id = $this->get_option( 'merchant_id' );
$this->merchant_password = trim($this->get_option( 'merchant_password' ));
$this->merchant_secret = $this->get_option( 'merchant_secret' );
$this->test_mode = $this->get_option('test_mode');
$this->timeout_in_days = $this->get_option('timeout_in_days');
$this->debug = $this->get_option('debug');
$this->pay_method = "Paypro";
if($this->timeout_in_days==='yes'){
$this->timeout = trim($this->get_option( 'merchant_timeout_days' ));
}
else{
$this->timeout = trim($this->get_option( 'merchant_timeout_minutes' ));
}
if($this->test_mode==='yes'){
$this->api_url = 'https://demoapi.paypro.com.pk';
}
else{
$this->api_url = 'https://api.paypro.com.pk';
}
$this->init_form_fields();
$this->init_settings();
self::$log_enabled = $this->debug;
// Save options
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
// Payment listener/API hook
add_action( 'woocommerce_api_wc_gateway_mib_paypro', array( $this, 'paypro_response' ) );
}
function init_form_fields(){
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Yes', 'woocommerce' ),
'default' => 'yes'
),
'merchant_id' => array(
'title' => __( 'Merchant Username', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This Merchant Username Provided by PayPro', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
),
'test_mode' => array(
'title' => __( 'Enable Test Mode', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Yes', 'woocommerce' ),
'default' => 'yes'
),
'merchant_password' => array(
'title' => __( 'Merchant Password', 'woocommerce' ),
'type' => 'password',
'description' => __( 'Merchant Password Provided by PayPro', 'woocommerce' ),
'default' => __( '', 'woocommerce' ),
'desc_tip' => true,
),
'merchant_secret' => array(
'title' => __( 'Secret Key', 'woocommerce' ),
'type' => 'password',
'description' => __( 'Any Secret Key Or Word with No Spaces', 'woocommerce' ),
'default' => __( rand(), 'woocommerce' ),
'desc_tip' => true,
),
'merchant_timeout_minutes' => array(
'title' => __( 'Timeout (In Minutes)', 'woocommerce' ),
'type' => 'number',
'description' => __( 'Timeout Before order expires it can be between 5 to 30 minutes', 'woocommerce' ),
'default' => __( 5, 'woocommerce' ),
'desc_tip' => true,
'custom_attributes' => array(
'min' => 5,
'max' => 30
)
),
'timeout_in_days' => array(
'title' => __( 'Enable Timeout in days', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Yes', 'woocommerce' ),
'default' => 'no'
),
'merchant_timeout_days' => array(
'title' => __( 'Timeout (In Days)', 'woocommerce' ),
'type' => 'number',
'description' => __( 'Minimum 1 day Max 3 Days. Remember, It works as due date you\'ve selected 1 day the expiration date of the PayPro id will be set as the day after today.', 'woocommerce' ),
'default' => __( 1, 'woocommerce' ),
'desc_tip' => true,
'custom_attributes' => array(
'min' => 1,
'max' => 3
)
),
'debug' => array(
'title' => __( 'Debug Log', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable logging', 'woocommerce' ),
'default' => 'no',
'description' => sprintf( __( 'Debug Information <em>%s</em>', 'woocommerce' ), wc_get_log_file_path( 'paypro' ) )
),
);
}
/**
* Logging method
* #param string $message
*/
public static function log( $message ) {
if ( self::$log_enabled ) {
if ( empty( self::$log ) ) {
self::$log = new WC_Logger();
}
$message = is_array($message) ? json_encode($message) : $message;
self::$log->add( 'paypro', $message );
}
}
/**
* Process the payment and return the result
*
* #access public
* #param int $order_id
* #return array
*/
function process_payment( $order_id ) {
$order = new WC_Order( $order_id );
$paypro_args = $this->get_paypro_args( $order );
$paypro_args = http_build_query( $paypro_args, '', '&' );
$this->log("========== Payment Processing Started: args =========");
$this->log($paypro_args);
//if demo is enabled
$checkout_url = $this->checkout_url;;
return array(
'result' => 'success',
// 'redirect' => 'http://localhost:8000/secureform?'.$paypro_args
'redirect' => 'https://marketplace.paypro.com.pk/secureform?'.$paypro_args
);
}
/**
* Get PayPro Args for passing to PP
*
* #access public
* #param mixed $order
* #return array
*/
function get_paypro_args( $order ) {
global $woocommerce;
$order_id = $order->get_id();
//Encrypting the username and password
$token1 = $this->merchant_id;
$token2 = $this->merchant_password;
$cipher_method = 'aes-128-ctr';
$secret_word = md5($this->merchant_secret);
$enc_key = openssl_digest($secret_word.date('d/m/y'), 'SHA256', TRUE);
$enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));
$crypted_token1 = openssl_encrypt($token1, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
$crypted_token2 = openssl_encrypt($token2, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
unset($token, $cipher_method, $enc_key, $enc_iv);
// PayPro Args
$paypro_args = array(
'mid' => $crypted_token1,
'mpw' => $crypted_token2,
'secret_public' => base64_encode($this->merchant_secret),
'is_encrypted' => 1,
'mode' => $this->test_mode,
'timeout_in_days' => $this->timeout_in_days,
'merchant_order_id' => $order_id,
'merchant_name' => get_bloginfo( 'name' ),
'request_is_valid' => 'true',
'request_from' => 'woocommerce',
// Billing Address info
'first_name' => $order->get_billing_first_name(),
'last_name' => $order->get_billing_last_name(),
'street_address' => $order->get_billing_address_1(),
'street_address2' => $order->get_billing_address_2(),
'city' => $order->get_billing_city(),
'state' => $order->get_billing_state(),
'zip' => $order->get_billing_postcode(),
'country' => $order->get_billing_country(),
'email' => $order->get_billing_email(),
'phone' => $order->get_billing_phone(),
);
if (!function_exists('is_plugin_active')) {
include_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
if(is_plugin_active( 'custom-order-numbers-for-woocommerce/custom-order-numbers-for-woocommerce.php' )){
$paypro_args['paypro_order_id'] = time().'-'.get_option( 'alg_wc_custom_order_numbers_counter', 1 );
}
else{
$paypro_args['paypro_order_id'] = time().'-'.$order_id;
}
// Shipping
if ($order->needs_shipping_address()) {
$paypro_args['ship_name'] = $order->get_shipping_first_name().' '.$order->get_shipping_last_name();
$paypro_args['company'] = $order->get_shipping_company();
$paypro_args['ship_street_address'] = $order->get_shipping_address_1();
$paypro_args['ship_street_address2'] = $order->get_shipping_address_2();
$paypro_args['ship_city'] = $order->get_shipping_city();
$paypro_args['ship_state'] = $order->get_shipping_state();
$paypro_args['ship_zip'] = $order->get_shipping_postcode();
$paypro_args['ship_country'] = $order->get_shipping_country();
}
$paypro_args['x_receipt_link_url'] = $this->get_return_url( $order );
$paypro_args['request_site_url'] = get_site_url();
$paypro_args['request_site_checkout_url'] = wc_get_checkout_url();
$paypro_args['return_url'] = $order->get_cancel_order_url();
$paypro_args['issueDate'] = date('d/m/Y');
$paypro_args['cartTotal'] = $order->get_total();
$paypro_args['store_currency'] = get_woocommerce_currency();
$paypro_args['store_currency_symbol'] = get_woocommerce_currency_symbol();
//Getting Cart Items
$billDetails= array();
$flag = 0;
foreach ($order->get_items() as $item => $values){
// Get the product name
$product_name = $values['name'];
// Get the item quantity
$item_quantity = $order->get_item_meta($item, '_qty', true);
// Get the item line total
$item_total = $order->get_item_meta($item, '_line_total', true);
$price = $item_total/$item_quantity;
$billDetails[$flag]['LineItem'] = esc_html($product_name);
$billDetails[$flag]['Quantity'] = $item_quantity;
$billDetails[$flag]['UnitPrice'] = $price;
$billDetails[$flag++]['SubTotal'] = $item_total;
}
$paypro_args['cartItemList'] = urlencode(json_encode($billDetails));
////
//setting payment method
if ($this->pay_method)
$paypro_args['pay_method'] = $this->pay_method;
//if test_mode is enabled
if ($this -> test_mode == 'yes'){
$paypro_args['test_mode'] = 'Y';
}
//if timeout_in_days is enabled
if ($this -> timeout_in_days == 'yes'){
$paypro_args['timeout'] = $this->timeout;
}
else{
$paypro_args['timeout'] = $this->timeout*60;
}
$paypro_args = apply_filters( 'woocommerce_paypro_args', $paypro_args );
return $paypro_args;
}
/**
* this function is return product object for two
* different version of WC
*/
function get_product_object(){
return $product;
}
/**
* Check for PayPro IPN Response
*
* #access public
* #return void
*/
function paypro_response() {
global $woocommerce;
// woocommerce_log($_REQUEST);
$this->log(__("== INS Response Received == ", "PayPro") );
$this->log( $_REQUEST );
$wc_order_id = '';
if( !isset($_REQUEST['merchant_order_id']) ) {
if( !isset($_REQUEST['vendor_order_id']) ) {
$this->log( '===== NO ORDER NUMBER FOUND =====' );
exit;
} else {
$wc_order_id = $_REQUEST['vendor_order_id'];
}
} else {
$wc_order_id = $_REQUEST['merchant_order_id'];
}
$this->log(" ==== ORDER -> {$wc_order_id} ====");
// echo $wc_order_id;
$wc_order_id = apply_filters('woocommerce_order_no_received', $wc_order_id, $_REQUEST);
$this->log( "Order Received ==> {$wc_order_id}" );
// exit;
$wc_order = new WC_Order( absint( $wc_order_id ) );
$this->log("Order ID {$wc_order_id}");
$this->log("WC API ==> ".$_GET['wc-api']);
// If redirect after payment
if( isset($_GET['key']) && (isset($_GET['wc-api']) && strtolower($_GET['wc-api']) == 'wc_gateway_mib_paypro') ) {
$this->verify_order_by_hash($wc_order_id);
exit;
}
$message_type = isset($_REQUEST['message_type']) ? $_REQUEST['message_type'] : '';
$sale_id = isset($_REQUEST['sale_id']) ? $_REQUEST['sale_id'] : '';
$invoice_id = isset($_REQUEST['invoice_id']) ? $_REQUEST['invoice_id'] : '';
$fraud_status = isset($_REQUEST['fraud_status']) ? $_REQUEST['fraud_status'] : '';
$this->log( "Message Type/Fraud Status: {$message_type}/{$fraud_status}" );
switch( $message_type ) {
case 'ORDER_CREATED':
$wc_order->add_order_note( sprintf(__('ORDER_CREATED with Sale ID: %d', 'woocommerce'), $sale_id) );
$this->log(sprintf(__('ORDER_CREATED with Sale ID: %d', 'woocommerce'), $sale_id));
break;
case 'FRAUD_STATUS_CHANGED':
if( $fraud_status == 'pass' ) {
// Mark order complete
$wc_order->payment_complete();
$wc_order->add_order_note( sprintf(__('Payment Status Clear with Invoice ID: %d', 'woocommerce'), $invoice_id) );
$this->log(sprintf(__('Payment Status Clear with Invoice ID: %d', 'woocommerce'), $invoice_id));
add_action('woocommerce_order_completed', $order, $sale_id, $invoice_id);
} elseif( $fraud_status == 'fail' ) {
$wc_order->update_status('failed');
$wc_order->add_order_note( __("Payment Declined", 'woocommerce') );
$this->log( __("Payment Declined", 'woocommerce') );
}
break;
}
exit;
}
function verify_order_by_hash($wc_order_id) {
global $woocommerce;
#ob_clean();
$paypro_id = $_REQUEST['paypro_id'];
$tpaycode = $_REQUEST['tpaycode'];
$order_id = $_REQUEST['merchant_order_id'];
$wc_order = wc_get_order( $wc_order_id );
// $order_total = isset($_REQUEST['total']) ? $_REQUEST['total'] : '';
$order_total = $wc_order->get_total();
$compare_string = $this->merchant_id . $paypro_id . $order_total;
$compare_hash1 = strtoupper(md5($compare_string));
$this->log("Compare String ===>" .$compare_string);
$compare_hash2 = $_REQUEST['key'];
if ($compare_hash1 != $compare_hash2) {
$this->log("Hash_1 ==> {$compare_hash1}");
$this->log("Hash_2 ==> {$compare_hash2}");
wp_die( "PayPro Hash Mismatch... check your secret word." );
} else {
//Curl Request
$url = $this->api_url.'/cpay/gos?userName=' . $this->merchant_id . '&password=' . $this->merchant_password . '&cpayId=' . $tpaycode;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
// Submit the GET request
$result = curl_exec($ch);
if (curl_errno($ch)) //catch if curl error exists and show it
echo 'Curl error: ' . curl_error($ch);
else {
//Check if the order ID passed is the same or fake
$res = json_decode($result, true);
$returnedOrderID = explode('-',$res[1]['OrderNumber']);
if ($returnedOrderID[1]===$order_id) {
if (strtoupper($res[1]['OrderStatus']) == "PAID") {
$wc_order->add_order_note( sprintf(__('Payment completed via PayPro Order Number %d', 'paypro'), $tpaycode) );
// Mark order complete
$wc_order->payment_complete();
// Empty cart and clear session
$woocommerce->cart->empty_cart();
$order_redirect = add_query_arg('paypro','processed', $this->get_return_url( $wc_order ));
// Close cURL session handle
curl_close($ch);
wp_redirect( $order_redirect );
exit;
} elseif (strtoupper($res[1]['OrderStatus']) == "BLOCKED") {
$wc_order->add_order_note( sprintf(__('Error processing the payment of Order Number %d', 'paypro'), $tpaycode) );
$order_redirect = add_query_arg('paypro','canceled', $wc_order->get_cancel_order_url());
// Close cURL session handle
curl_close($ch);
wp_redirect( $order_redirect );
exit;
}
elseif (strtoupper($res[1]['OrderStatus']) == "UNPAID") {
$wc_order->add_order_note( sprintf(__('Error processing the payment of Order Number %d', 'paypro'), $tpaycode) );
$order_redirect = add_query_arg('paypro','pending', $wc_order->get_cancel_order_url());
// Close cURL session handle
curl_close($ch);
wp_redirect( $order_redirect );
exit;
}
}
}
}
}
function get_price($price){
$price = wc_format_decimal($price, 2);
return apply_filters('mib_get_price', $price);
}
}
}
function add_mib_payment_gateway( $methods ) {
$methods[] = 'WC_Gateway_MIB_PayPro';
return $methods;
}
add_filter( 'woocommerce_payment_gateways', 'add_mib_payment_gateway' );
function payproco_log( $log ) {
if ( true === WP_DEBUG ) {
if ( is_array( $log ) || is_object( $log ) ) {
$resp = error_log( print_r( $log, true ), 3, plugin_dir_path(__FILE__).'payproco.log' );
} else {
$resp = error_log( $log, 3, plugin_dir_path(__FILE__).'payproco.log' );
}
var_dump($resp);
}
}
I am really stuck and have tried every email hook under the sun. I used an outdated PHP code developed by someone else and revised it for new woocommerce hooks (as the code is 4years old). Everything works perfectly but i need the customer field "billing_vat" to appear in the new order admin email. I will share my code and any help will be greatly appreciated please!!
Thanks
//create vat number billing field
add_filter('woocommerce_billing_fields' , 'display_billing_vat_fields');
function display_billing_vat_fields($billing_fields){
$billing_fields['billing_vat'] = array(
'type' => 'text',
'label' => __('VAT number', 'woocommerce' ),
'class' => array('form-row-wide'),
'required' => false,
'clear' => true,
'priority' => 30, // To change the field location increase or decrease this value
);
return $billing_fields;
}
// Printing the Billing Address on My Account
add_filter( 'woocommerce_my_account_my_address_formatted_address',
'custom_my_account_my_address_formatted_address', 10, 3 );
function custom_my_account_my_address_formatted_address( $fields, $customer_id, $type ) {
if ( $type == 'billing' ) {
$fields['vat'] = get_user_meta( $customer_id, 'billing_vat', true );
}
return $fields;
}
// Checkout -- Order Received (printed after having completed checkout)
add_filter( 'woocommerce_order_formatted_billing_address',
'custom_add_vat_formatted_billing_address', 10, 2 );
function custom_add_vat_formatted_billing_address( $fields, $order ) {
$fields['vat'] = $order->get_meta('billing_vat');
return $fields;
}
// Creating merger VAT variables for printing formatting
add_filter( 'woocommerce_formatted_address_replacements',
'custom_formatted_address_replacements', 10, 2 );
function custom_formatted_address_replacements( $replacements, $args ) {
$replacements['{vat}'] = ! empty($args['vat']) ? $args['vat'] : '';
$replacements['{vat_upper}'] = ! empty($args['vat']) ? strtoupper($args['vat']) : '';
return $replacements;
}
//Defining the Spanish formatting to print the address, including VAT.
add_filter( 'woocommerce_localisation_address_formats', 'custom_localisation_address_format' );
function custom_localisation_address_format( $formats ) {
foreach($formats as $country => $string_address ) {
$formats[$country] = str_replace('{company}\n', '{company}\n{vat_upper}\n', $string_address);
}
return $formats;
}
add_filter( 'woocommerce_customer_meta_fields', 'custom_customer_meta_fields' );
function custom_customer_meta_fields( $fields ) {
$fields['billing']['fields']['billing_vat'] = array(
'label' => __( 'VAT number', 'woocommerce' )
);
return $fields;
}
add_filter( 'woocommerce_admin_billing_fields', 'custom_admin_billing_fields' );
function custom_admin_billing_fields( $fields ) {
$fields['vat'] = array(
'label' => __( 'VAT number', 'woocommerce' ),
'show' => true
);
return $fields;
}
add_filter( 'woocommerce_found_customer_details', 'custom_found_customer_details' );
function custom_found_customer_details( $customer_data ) {
$customer_data['billing_vat'] = get_user_meta( $_POST['user_id'], 'billing_vat', true );
return $customer_data;
}
add_filter('woocommerce_email_order_meta_fields', 'supine_add_email_order_meta_fields', 10, 3 );
function supine_add_email_order_meta_fields( $fields, $sent_to_admin, $order_obj ) {
$billing = get_post_meta( $order_obj->get_order_number(), 'billing_vat', true );
return $fields;
}
Shortly after posting this, i found a fix for it. I had to define the new key "billing_vat" so that it posted with other user information. All the code above is correct except the last add_filter hook. Replace that with the following code, and you have added an optional vat_number field to your checkout, admin backend as well as order emails. Here's the code snippet to replace last "add_filter" hook:
// VAT Number in emails
add_filter( 'woocommerce_email_order_meta_keys',
'supine_vat_number_display_email' );
function supine_vat_number_display_email( $keys ) {
$keys['VAT Number'] = '_billing_vat';
return $keys;
}
code goes in functions.php of your active child theme. Tested and working.
I have a custom post type built in WordPress named Knowledge.
Knowledge currently only has 4 posts in total. By default, 3 posts are shown, then on load more click, I want the last, 4th blog card to show.
However, currently, my AJAX request isn't succeeding, it gives me the /wp-admin/admin-ajax.php 403 (Forbidden) error. Similar questions stated that it might be related to security plugins. However, I have disabled any security related plugins (Jetpack) and the error still exists.
Here is my approach so far:
knowledge-listing.php
<?php
global $post;
$args = array(
'post_type' => 'knowledge',
'posts_per_page' => 3,
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC'
);
$query = new WP_Query($args);
if ($query->have_posts()):
while ($query->have_posts()):
$query->the_post();
get_part('templates/snippets/knowledge-card', array(
'heading' => get_the_title() ,
'subheading' => get_the_excerpt() ,
'background' => wp_get_attachment_url(get_post_thumbnail_id($post->ID)) ,
));
endwhile;
wp_reset_postdata(); ?>
<div class="knowledgeListing__loadmore">
<a href="#" id="loadmore" class="button--loadmore" data-type="knowledge" data-max-num-pages="<?php echo $query->max_num_pages; ?>">
<?php echo _e('Load More', 'theme'); ?>
</a>
</div>
<?php
endif; ?>
loadmore.js
jQuery(function($){
$(document).ready(function(){
$("#loadmore").on('click', function (e) {
e.preventDefault();
var btn = $(this);
showNextItems(btn);
});
function showNextItems(btn) {
var max_num_pages = btn.data('max-num-pages');
var post_type = btn.data('type');
var button = btn,
data = {
'action':'loadmore',
'query': loadmore_params.posts,
'page' : loadmore_params.current_page,
// 'security' : loadmore_params.security,
// 'max_num_pages' : max_num_pages,
// 'post_type' : post_type
};
$.ajax({
url : loadmore_params.ajaxurl,
data : data,
type : 'POST',
beforeSend : function ( xhr ) {
button.text('Loading...');
},
success : function( data ){
if( data ) {
button.text( 'Load More' ).prev().before(data);
loadmore_params.current_page++;
$('.knowledgeListing__wrapper').find('.knowledgeCard').last().after( data );
if ( loadmore_params.current_page == max_num_pages ){
button.remove();
}
console.log("success");
} else {
button.remove();
}
},
error : function(error){
button.text( 'Load More' );
console.table("Data: " + data);
console.table("loadmore_params: " + loadmore_params);
// console.log(error);
}
});
}
});
});
The following two console.log's spit out [object Object]
console.table("Data: " + data);
console.table("loadmore_params: " + loadmore_params);
Unsure where things are going wrong?
Edit:
console.log("Data:", data) and console.log("loadmore_params:", loadmore_params); results below:
On further inspection, when trying to access the /wp-admin/admin-ajax.php url, I see a 0. When searching for this online, it has been suggested to use die(). However, when I've added die() to the end of knowledge-listing.php, it still shows me a 0.
Here is my localized script for reference:
global $wp_query;
wp_localize_script( 'theme', 'loadmore_params', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'posts' => json_encode( $wp_query->query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
'max_page' => $wp_query->max_num_pages,
'security' => wp_create_nonce("load_more")
) );
And actions:
add_action('wp_ajax_loadmore', 'pagination_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'pagination_ajax_handler'); // wp_ajax_nopriv_{action}
Just my 2 cents but "loadmore" as an action name is quite common and may be used by some other plugins/theme function. You should really consider switching to something namespaced like wp_ajax_mypluginname_loadmore.
That said, another common issue is that you perform the add_actions too late or maybe they never get hit by code before wp-admin-ajax does his thing.
Please be 100% you hit the add_actions BEFORE the code enter wp-admin-ajax.
To make a quick test you could move those line (included the function) in your child-theme functions.php file
I use the following snippet to create a WordPress post via the REST API, using the Node.js wrapper:
var wp = new WPAPI({
endpoint: 'http://your-site.com/wp-json',
username: 'someusername',
password: 'password'
});
wp.posts().create({
title: 'Your Post Title',
content: 'Your post content',
status: 'publish',
meta: { "custom_field": "my custom field value" }
}).then(function( response ) {
console.log( response.id );
})
When fetching the posts, the meta is empty.
Why is that and how can I fix that?
For some reason that did not work for me either. I ended by using a WordPress REST hook.
In functions.php I added:
add_filter( 'pre_post_update' , function ( $post_id , $post ) {
$body = json_decode(file_get_contents('php://input'), true);
$meta_fields = $body["meta"];
foreach ($meta_fields as $meta_key => $value) {
update_post_meta($post_id, $meta_key, $value);
}
}, '99', 2 );
The snippet above will parse the meta field and will update the post metadata fields.
If you want to include the custom fields in the responses, you can use:
//Get custom fields via Rest API
add_action( 'rest_pre_echo_response', function( $response, $object, $request ) {
//* Get the post ID
$post_id = $response[ 'id' ];
if ($response['type'] !== 'post' && $response['type'] !== 'page') return $response;
$response['custom_fields'] = get_post_meta($post_id);
return $response;
}, 10, 3 );
I am currently creating a login form in PHP PDO and I am using ajax to display the relevant messages on screen, e.g.
"Logging in..."
"Some input fields are empty"
"Your username is required"
"Your password is required"
Validation such as checking if input fields are empty is working fine along with when login credentials appear to be incorrect however when I login with correct credentials I just get message "Logging in..." and nothing happens, I don't even think it sets the session. I have also added a token to prevent CSRF and was just wondering if i'm using it correctly.
I'm unsure of what is causing my code not to proceed with logging in.
my ajax script:
<script type='text/javascript'>
$(document).ready(function () {
var submitButton = $("#btn-login");
submitButton.on('click', function (e) {
e.preventDefault();
// Get input field values of the contact form
var loginFormInputs = $('#login-form :input'),
userName = $('#txt_uname_email').val(),
userPassword = $('#txt_password').val(),
token = $('#token').val(),
alertMessage = $('#login-alert-message');
// Disable Inputs and display a loading message
alertMessage.html('<p style="opacity: 1"><i class="fa fa-spinner fa-spin text-success"></i> Logging in..</p>');
submitButton.html('<i class="fas fa-spinner fa-spin"></i>');
loginFormInputs.prop("disabled", true);
// Data to be sent to server
var post_data = {
'form': 'loginForm',
'userName': userName,
'userPassword': userPassword,
'token': token
};
// Ajax post data to server
$.post('./api', post_data, function (response) {
// Load jsn data from server and output message
if (response.type === 'error') {
alertMessage.html('<p><i class="fa-lg far fa-times-circle text-danger"></i> ' + response.text + '</p>');
submitButton.html('Login');
loginFormInputs.prop("disabled", false);
} else {
alertMessage.html('<p><i class="fa-lg far fa-check-circle text-success"></i> ' + response.text + '</p>');
submitButton.html('Login');
window.location = "dashboard";
}
}, 'json');
});
});
</script>
My login function (class.user.php) which is used in api.php:
public function doLogin($uname,$umail,$upass)
{
try
{
$stmt = $this->conn->prepare("SELECT * FROM `settings` LIMIT 1");
$stmt->execute();
$mainten=$stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $this->conn->prepare("SELECT user_id, user_name, user_email, user_pass, status FROM users WHERE user_name=:uname OR user_email=:umail ");
$stmt->execute(array(':uname'=>$uname, ':umail'=>$umail));
$userRow=$stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() == 1)
{
if(password_verify($upass, $userRow['user_pass']))
{
session_regenerate_id(false);
return ["correctPass"=>true, "banned"=> ($userRow['status']== 1) ? true : false, "maintenance"=> ($mainten["maintenance"]== 1) ? true : false];
}
else
{
return ["correctPass"=>false];
}
}
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
api.php:
//include class.user.php here and set $login = new USER();
//set $uname, $umail, $upass, $token vars here
if( $_POST && $_POST["form"] === 'loginForm' ) {
// Use PHP To Detect An Ajax Request code is here
// Checking if the $_POST vars well provided, Exit if there is one missing code is here
// PHP validation for the fields required code is here
$validation = $login->doLogin($uname,$umail,$upass);
if($validation["correctPass"]){
if($validation["maintenance"]){
if (!in_array($uname, array('admin'))){
$output = json_encode(
array(
'type' => 'error',
'text' => 'Website under maintenance.'
));
die($output);
}
}
if($validation["banned"]){
$output = json_encode(
array(
'type' => 'error',
'text' => 'User has been banned.'
));
die($output);
}else{
if(Token::check($_POST['token'])) {
$stmtt = $login->runQuery("SELECT user_id FROM users WHERE user_name=:uname OR user_email=:umail ");
$stmtt->execute(array(':uname'=>$uname, ':umail'=>$umail));
$userRow=$stmtt->fetch(PDO::FETCH_ASSOC);
$_SESSION['user_session'] = $userRow['user_id'];
$output = json_encode(
array(
'type' => 'message',
'text' => 'Logged in successfully.'
));
die($output);
//$success = "Logged in successfully, redirecting..";
//header( "refresh:3;url=ab" );
//$login->redirect('dashboard');
} else {
$output = json_encode(
array(
'type' => 'error',
'text' => 'Unexpected error occured.'
));
die($output);
}
}
}
else{
$output = json_encode(
array(
'type' => 'error',
'text' => 'Incorrect username or password.'
));
die($output);
}
}