I am developing wordpress plugin for Woocommerce payment.
As I can see I have to extend WC_Payment_Gateway and implement method "process_payment". I have looked into some examples and found that this method should return something like:
array(
'result' => 'success',
'redirect' => $redirectUrl
);
and then control is returned to WC_Checkout which will redirect to provided url.
Problem is that our payment provider requires to submit form to his page instead of redirect. Having that API restriction in mind I am asking what is the best way to connect with my payment provider?
Is there a way to submit form instead of redirection?
You can achieve it as illustrated and commented below by extending the WooCommerce WC_Payment_Gateway class with the following methods:
public function __construct() {
$this->id = 'my-payment-gateway';
$this->icon = plugins_url( '/path/to/image.extension', __FILE__ );
$this->has_fields = true;
$this->method_title = __( 'My Payment Gateway', 'txdomain' );
$this->method_description = __( 'Add some descriptions here.', 'txdomain' );
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array(
$this,
'process_admin_options'
) );
// below is the hook you need for that purpose
add_action( 'woocommerce_receipt_' . $this->id, array(
$this,
'pay_for_order'
) );
}
// here, your process payment method, returning the pay for order page
// where you will can submit the form to your payment gateway providers' page
public function process_payment( $order_id ) {
$order = new WC_Order( $order_id );
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url( true )
);
}
// here, prepare your form and submit it to the required URL
public function pay_for_order( $order_id ) {
$order = new WC_Order( $order_id );
echo '<p>' . __( 'Redirecting to payment provider.', 'txtdomain' ) . '</p>';
// add a note to show order has been placed and the user redirected
$order->add_order_note( __( 'Order placed and user redirected.', 'txtdomain' ) );
// update the status of the order should need be
$order->update_status( 'on-hold', __( 'Awaiting payment.', 'txtdomain' ) );
// remember to empty the cart of the user
WC()->cart->empty_cart();
// perform a click action on the submit button of the form you are going to return
wc_enqueue_js( 'jQuery( "#submit-form" ).click();' );
// return your form with the needed parameters
return '<form action="' . 'https://example.com' . '" method="post" target="_top">
<input type="hidden" name="merchant_key" value="">
<input type="hidden" name="success_url" value="">
<input type="hidden" name="cancelled_url" value="">
<input type="hidden" name="deferred_url" value="">
<input type="hidden" name="invoice_id" value="">
<input type="hidden" name="total" value="">
<div class="btn-submit-payment" style="display: none;">
<button type="submit" id="submit-form"></button>
</div>
</form>';
}
Related
i have following issue with woocommerce/dokan:
I created a custom field for product variation:
custom field in wordpress backend
It works fine, the values are storing and i can change the value at the backend. Therefor i added following lines of code into function.php of theme file:
function variation_settings_fields( $loop, $variation_data, $variation ) {
// Text Field
woocommerce_wp_text_input(
array(
'id' => '_text_field[' . $variation->ID . ']',
'label' => __( 'My Text Field', 'woocommerce' ),
'placeholder' => 'http://',
'desc_tip' => 'true',
'description' => __( 'Enter the custom value here.', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_text_field', true )
)
);
}
/**
* Save new fields for variations
*
*/
function save_variation_settings_fields( $post_id ) {
// Text Field
$text_field = $_POST['_text_field'][ $post_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $post_id, '_text_field', esc_attr( $text_field ) );
}
}
// Add New Variation Settings
add_filter( 'woocommerce_available_variation', 'load_variation_settings_fields' );
/**
* Add custom fields for variations
*
*/
function load_variation_settings_fields( $variations ) {
// duplicate the line for each field
$variations['text_field'] = get_post_meta( $variations[ 'variation_id' ], '_text_field', true );
return $variations;
}
So far, so good. I can set a value and the value can be saved over the backend.
Now i want to change the custom field for this product variation in dokan vendor dashboard. I duplicated html-product-variation.php file into child theme and added the new field:
dokan vendor dashboard product variation
with following code:
<div>
<p class="dokan-form-group">
<label><?php esc_html_e( 'Custom Textfield', 'dokan' ); ?></label>
<textarea class="dokan-form-control" name="_text_field[<?php echo esc_attr( $loop ); ?>]" rows="3" style="width:100%;"><?php echo isset( $variation_data['_text_field'] ) ? esc_textarea( $variation_data['_text_field'] ) : ''; ?></textarea>
</p>
</div>
The problem is, that the value, which i set in the backend isn't shown and if i inspect the variation_data object there is no key in the array which says "_text_field". How can i store/update variation_data object?
I hope it's understandable which issue i'm facing here and look forward to some help :)
Best wishes,
Florian
I'm trying to make the login form in checkout page visible without the toggle
here is what form-login.php looks like
<div class="woocommerce-form-login-toggle">
<?php wc_print_notice( apply_filters( 'woocommerce_checkout_login_message', esc_html__( 'Returning customer?', 'woocommerce' ) ) . ' ' . esc_html__( 'Click here to login', 'woocommerce' ) . '', 'notice' ); ?>
</div>
I need to remove that toggle and make the login form always visible
Thank you
I found the answer here
Unhide Checkout Login form for unlogged users in Woocommerce
users-in-woocommerce
// Enable the login form by default for unlogged users
add_action( 'woocommerce_before_checkout_form', 'force_checkout_login_for_unlogged_customers', 4 );
function force_checkout_login_for_unlogged_customers() {
if( ! is_user_logged_in() ) {
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_login_form', 10 );
add_action( 'woocommerce_before_checkout_form', 'custom_checkout_login_form', 20 );
}
}
function custom_checkout_login_form() {
wc_get_template( 'global/form-login.php', array(
'message' => __( 'If you have shopped with us before, please enter your details below. If you are a new customer, please proceed to the Billing & Shipping section.', 'woocommerce' ),
'redirect' => wc_get_page_permalink( 'checkout' ),
'hidden' => false,
) );
}
I'm very new to payment gateway integration. I learned that, orders can be created programmatically without adding products in woocommerce and done that.
Problem now is, I'm not sure how to automate the payment process once submit order button is clicked.
Currently when the order form is submitted, I create order programmatically into woocommerce and expect the user to redirected to selected(currently by default is billPlz) payment gateway page to make payment.
I already had woocomerce and billPlz payment gateway installed. And WC()->payment_gateways->get_available_payment_gateways() does return me the billPlz.
However the payment form is not shown from the payment gateway for users to submit the payment into the billPlz.
I see 'success' message and redirected to mydomain/order-received/72?key=wc_order_5a0f8f3ead251
I assume this is the Thank you page?
How to redirect to payment gateway when order is created?
Order form (my own, not from woocomerce)
<form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="POST">
<input type="text" name="action" value="createOrder">
<input type="text" name="booking_id" value="123">
<input type="text" name="customer_id" value="1006">
<input type="text" name="order_amount" value="180.00">
<input type="text" name="order_status" value="1">
<input type="submit" value="PROCEED TO MAKE PAYMENT">
</form>
create order function
public function createOrder()
{
$product_id = 222;
$quantity = 1;
$args = array(
'variation' => array( 'attribute_color' => 'red'),
'status' => 'complete',
'customer_id'=> 23
);
$order = wc_create_order();
$order_id = trim(str_replace('#', '', $order->get_order_number()));
$order->add_product( get_product( $product_id ), $quantity, $args );
$order->set_status( $args['status'] );
$order->set_customer_id( is_numeric( $args['customer_id'] ) ? absint( $args['customer_id'] ) : 0 );
$order->set_total( ($discount['amount']/100) , 'order_discount'); // not pennies (use dollar amount)
update_post_meta( $order_id, '_payment_method', 'billplz' );
update_post_meta( $order_id, '_payment_method_title', 'Billplz Payment Gateway' );
$order->calculate_totals();
// Process Payment
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$result = $available_gateways[ 'billplz' ]->process_payment( $order_id );
// Redirect to success/confirmation/payment page
if ( $result['result'] == 'success' ) {
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );
$return_url = $available_gateways[ 'billplz' ]->get_return_url( $order );
wp_redirect($return_url);
exit;
}
}
You can generate a payment URL for unpaid orders like it appears in your My Account page under the Orders TAB by using the following orders function.
$order->get_checkout_payment_url()
I know this is a common error but I haven't come across any solutions that have worked. I'm creating a plugin that uses custom post types and I have a settings page under that CPT's menu. The settings page displays fine but when I go to save the settings I get the error ERROR: options page not found. Here is my settings class:
class Settings {
private $view;
public function __construct( $view ) {
$this->view = $view;
add_action( 'admin_menu', array( $this, 'submenu' ) );
add_action( 'admin_init', function () {
add_settings_section(
'saw_hours',
'Hours Settings', // Title
array( $this, 'settings' ),
'saw_hours_settings'
);
} );
}
public function submenu()
{
add_submenu_page(
"edit.php?post_type=saw_hours", // Parent slug
"Settings", // Page title
"Settings", // Menu title
"activate_plugins", // Role required
'saw_hours_settings', // Menu slug
array($this->view, 'admin'));
}
public function settings()
{
// API key setting
register_setting(
'saw_hours',
'saw_hours_api_key'
);
add_settings_field(
'saw_hours_api_key',
'Set API Key:',
function(){
$clientId = get_option('saw_hours_api_key');
echo '<input type="text" name="saw_hours_api_key" value="' . $clientId . '" >';
},
'saw_hours_settings',
'saw_hours'
);
// Client ID setting
register_setting(
'saw_hours',
'saw_hours_client_id'
);
add_settings_field(
'saw_hours_client_id',
'Set Client ID:',
function(){
$clientId = get_option('saw_hours_client_id');
echo '<input type="text" name="saw_hours_client_id" value="' . $clientId . '" >';
},
'saw_hours_settings',
'saw_hours'
);
}
}
And here is the form page:
<form method="POST" action="options.php">
<?php settings_fields( 'saw_hours' ); ?>
<?php do_settings_sections( 'saw_hours_settings'); ?>
<?php submit_button(); ?>
</form>
I'm at a loss, any help would be appreciated.
Found an answer here:
https://wordpress.stackexchange.com/questions/139660/error-options-page-not-found-on-settings-page-submission-for-an-oop-plugin
This doesn't really answer why register_setting() isn't adding the property to the list of whitelisted properties. If anyone has a better understanding of what's going here I'd love to hear.
//Add phone number field to customer registration
add_filter( 'register_form', 'custom_phone_no_registration_field' );
function custom_phone_no_registration_field( ) {
echo '<div class="form-row form-row-wide"><label for="reg_phone">'.__('Phone Number', 'woocommerce').' <span class="required">*</span></label>
<input type="text" class="input-text" name="phone" id="reg_phone" size="30" value="'.esc_attr($_POST['phone']).'" /></div>';
}
//Validation registration form after submission using the filter registration_errors
add_action('registration_errors', 'custom_registration_errors_validation', 10,3);
function custom_registration_errors_validation($reg_errors, $sanitized_user_login, $user_email) {
global $woocommerce;
extract($_POST); // extracting $_POST into separate variables
if(empty($phone)) :
$woocommerce->add_error( __( 'Please, fill in all the required fields.', 'woocommerce' ) );
endif;
return $reg_errors;
}
I'm using register_form function to add a phone number field to registration form.it works but the registration_errors function is not working. Can anyone please help me with the code ?
I think you need to validate on the woocommerce_process_registration_errors filter. Take a look at process_registration() method in includes/class-wc-form-handler.php.
add_action( 'woocommerce_process_registration_errors', 'custom_registration_error' );
function custom_registration_errors( $validation_error ){
if ( ! isset( $_POST['phone'] ) ){
$validation_error = new WP_Error( 'phone-error', __( 'Please enter a phone number.', 'your-plugin' ) );
}
return $validation_error;
}