How do I correctly add additional options to a WooCommerce payment gateway's options page? - wordpress

I'm developing a plugin that will perform some functions when a particular payment gateway is present in WooCommerce, and it makes sense for my plugin options to be added to the same options page as the gateway's options. I don't want to change the behaviour of the gateway in any way, just display the options for my plugin on the same options page.
Based on this document, I came up with this code.
<?php
class MyPluginClass {
/**
* Initialise the class
**/
public function init() {
// Hook into the Payment tab of WooCommerce settings and add
// options to the Gateway's options page
// (Tab's ID is 'checkout' even though the tab is called payments)
add_filter( 'woocommerce_get_settings_checkout', array($this, 'add_options_to_gateway_options_page'), 10, 2 );
}
/**
* Add options to the gateway's options page
**/
public function add_options_to_gateway_options_page( $settings, $current_section_id ) {
// If the current section is not the required gateway, return the settings
// (replace gateway_id with the actual gateway ID. this is
// the 'section' argument from the URL when viewing the gateway's options page)
if ( 'gateway_id' != $current_section_id ) return $settings;
// Create settings
$my_settings = array(
array (
'title' => __('Automation options'),
'type' => 'title',
'description' => ''
),
array(
'id' => 'my_plugin_enabled',
'name' => 'my_plugin_enabled',
'title' => __('Gateway automations', 'my_plugin'),
'label' => __('Enable gateway automations', 'my_plugin'),
'description' => __('Enable the gateway automations plugin', 'my_plugin'),
'desc_tip' => true,
'type' => 'checkbox',
'default' => 'yes'
),
array(
'type' => 'sectionend',
'id' => 'my_plugin'
)
);
return $my_settings;
}
}
$myPlugin = new MyPluginClass;
$myPlugin->init();
The checkbox works and its value is saving to the DB and reading just fine on page load, along with the rest of the options on the page. The title and checkbox are displayed on the screen in the expected location and the checkbox is checked on the first load as per the default. But, the label and tooltip with the description are not displayed.
// The resulting HTML
<h2>Automation options</h2>
<table class="form-table">
<tbody>
<tr valign="top" class="">
<th scope="row" class="titledesc">Gateway automations</th>
<td class="forminp forminp-checkbox">
<fieldset>
<legend class="screen-reader-text"><span>Gateway automations</span></legend>
<label for="my_plugin_enabled">
<input name="my_plugin_enabled" id="my_plugin_enabled" type="checkbox" class="" value="1">
</label>
</fieldset>
</td>
</tr>
</tbody>
</table>
Am I doing something wrong or is there a bug somewhere?

Related

WooCommerce Shipping Plugin - Checkout Shipping Cost Not Updating(AJAX)

I've searched to find any solution but nothing worked.
Here what I want to do:
Add new field in checkout page called Shipping show as selectbox filled with Preorder and Non-preorder
If preorder then would show Location field show as selectbox
If non-preorder then would show Location field same as step 2 but different list option.
When Shipping and Location filled correctly, shipping cost would show with correct shipping cost.
Problem
When I filled all required field and Shipping, Location shipping cost wound calculate again. It do AJAX request, but shipping cost keep the same.
But, when I change Name or Street Address shipping cost updated correctly, which is bad behavior. When user click Place Order immediately would POST wrong shipping cost.
Here my Youtube Video to make clear what I ask for help.
What I did to create my own plugin:
Create custom field using hook something like this
public function woocommerce_checkout_fields( $fields )
{
// var_dump(have_rows('location', 'option'));
// die('test');
$options = [];
$options[''] = 'Select Shipping';
$options['pre-order'] = 'Pre Order';
if (!$this->hasPreorderItem()) {
$options['non-pre-order'] = 'Non Pre Order';
}
// Add custom billing shipping
$fields['billing']['billing_shipping'] = array (
'type' => 'select',
'label' => 'Shipping',
'placeholder' => 'Select shipping',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => true,
'options' => $options
// 'options' => $this->getLocations()
);
$fields['billing']['billing_location_pre_order'] = array (
'type' => 'select',
'label' => 'Location(Pre Order)',
'placeholder' => 'Select Preorder Location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->preorderLocations->getLocations()
// 'options' => $this->getLocations()
);
// Add custom billing location
$fields['billing']['billing_location'] = array (
'type' => 'select',
'label' => 'Location',
'placeholder' => 'Select location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->locations->getLocations()
// 'options' => $this->getLocations()
);
return $fields;
}
Create class to help calculate cost based on Shipping and Location.
What I have tried
Using this answer but no luck. Click here for the question.
Tried to make field to required, as I saw someone said it only update when all required fields filled.
Tried to disable cache in wp-config.php
I found solution from this link
I might help someone that has similar problem. You just need to clear the session. So, WooCommerce would re-calculate and recall your calculate_shipping() function.
To do that add woocommerce_checkout_update_order_review hook. It would look something like this
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);
function action_woocommerce_checkout_update_order_review( $posted_data )
{
global $woocommerce;
$packages = $woocommerce->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
}
}

WooCommerce custom payment method

I have to add a custom payment method to woocommerce.
this payment method has well documented JSON APIs.
how do I add a custom payment method, and hook it to the API?
The woocommerce_payment_gateways filter lets you add custom payment gateways to woocommerce.
add_filter( 'woocommerce_payment_gateways', 'add_your_gateway_class' );
function add_your_gateway_class( $methods ) {
$methods[] = 'WC_Custom_PG';
return $methods;
}
Next you create a class that extends the WC_Payment_Gateway class. In its constructor, you need to set the unique id, title and description for your payment gateway. You also need to initialize the form fields and the payment gateway settings.
The payment gateway class needs to be defined in a function that is called by the plugins_loaded hook
add_action( 'plugins_loaded', 'init_wc_custom_payment_gateway' );
function init_wc_custom_payment_gateway(){
class WC_Custom_PG extends WC_Payment_Gateway {
function __construct(){
$this->id = 'wc_custom_pg';
$this->method_title = 'Custom Payment Gateway';
$this->title = 'Custom Payment Gateway';
$this->has_fields = true;
$this->method_description = 'Your description of the payment gateway';
//load the settings
$this->init_form_fields();
$this->init_settings();
$this->enabled = $this->get_option('enabled');
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option('description');
//process settings with parent method
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
}
public function init_form_fields(){
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable Custom Payment Gateway',
'default' => 'yes'
),
'title' => array(
'title' => 'Method Title',
'type' => 'text',
'description' => 'This controls the payment method title',
'default' => 'Custom Payment Gatway',
'desc_tip' => true,
),
'description' => array(
'title' => 'Customer Message',
'type' => 'textarea',
'css' => 'width:500px;',
'default' => 'Your Payment Gateway Description',
'description' => 'The message which you want it to appear to the customer in the checkout page.',
)
);
}
function process_payment( $order_id ) {
global $woocommerce;
$order = new WC_Order( $order_id );
/****
Here is where you need to call your payment gateway API to process the payment
You can use cURL or wp_remote_get()/wp_remote_post() to send data and receive response from your API.
****/
//Based on the response from your payment gateway, you can set the the order status to processing or completed if successful:
$order->update_status('processing','Additional data like transaction id or reference number');
//once the order is updated clear the cart and reduce the stock
$woocommerce->cart->empty_cart();
$order->reduce_order_stock();
//if the payment processing was successful, return an array with result as success and redirect to the order-received/thank you page.
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
}
//this function lets you add fields that can collect payment information in the checkout page like card details and pass it on to your payment gateway API through the process_payment function defined above.
public function payment_fields(){
?>
<fieldset>
<p class="form-row form-row-wide">
<?php echo esc_attr($this->description); ?>
</p>
<div class="clear"></div>
</fieldset>
<?php
}
}
}
Once you activate your payment gateway plugin, you can enable the method in WooCommerce > Settings > Payments page.
For more information of payment gateway setup, you can visit : https://docs.woocommerce.com/document/payment-gateway-api/
You can either create this as a plugin or add the entire code to your theme's function.php file.
You need to write a plugin who embed your gateway API.
See more information on Woocomerce Documentation : Payment Gateway API
You can see further information about code/class/etc on the Woocomerce API Doc
thanks to both of you!
I also added these lines, otherwise I couldn't activate it:
add_filter('woocommerce_payment_gateways', 'weldpay_add_gateway_class');
function weldpay_add_gateway_class($gateways) {
$gateways[] = 'WC_Weldpay';
return $gateways;
}
there is the possibility to take information from the checkout, like items, name, surname, address, etc?

Add Field To Custom WP Login Form

I have a custom login form that I display on a page using the following:
$my_login_args = apply_filters( 'my_login_page_args', array(
'echo' => true,
'redirect' => site_url( $_SERVER['REQUEST_URI'] ),
'form_id' => 'my_login_form',
'label_username' => esc_html__( 'Email Address' ),
'label_password' => esc_html__( 'Password' ),
'label_remember' => esc_html__( 'Remember Me' ),
'label_log_in' => esc_html__( 'Sign In' ),
'id_username' => 'user_login',
'id_password' => 'user_pass',
'id_remember' => 'rememberme',
'id_submit' => 'wp-submit',
'remember' => true,
'value_username' => NULL,
'value_remember' => false
) );
wp_login_form( $my_login_args ); ?>
I need to pass a custom variable ($my_custom_id) stored in the login page through to the redirected page a user sees after login. Is there any way to append the URL with this variable using POST or GET or is the best solution to add this as a hidden field in the form?
Also, in terms of adding an extra field to the form I've tried adding a custom input box to the form using
add_action('login_form','my_added_login_field');
function my_added_login_field(){
//Output your HTML
?>
<p>
<label for="my_extra_field">My extra field<br>
<input type="text" tabindex="20" size="20" value="" class="input" id="my_extra_field" name="my_extra_field_name"></label>
</p>
<?php
}
However this only adds the field to the main Wordpress login and not my custom form. Any thoughts on how best to proceed?
You can you add custom field in login form at top, bottom, and in middle.
I have added login field in login_form_middle.
For Reference https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/general-template.php#L390
https://codex.wordpress.org/Customizing_the_Login_Form
/*
You can use these hooks as well to place your fields
login_form_bottom - login_form_top - login_form_middle
*/
add_filter('login_form_middle','my_added_login_field');
function my_added_login_field(){
//Output your HTML
$additional_field = '<div class="login-custom-field-wrapper"">
<label for="my_extra_field">My extra field<br>
<input type="text" tabindex="20" size="20" value="" class="input" id="my_extra_field" name="my_extra_field_name"></label>
</div>';
return $additional_field;
}

My CPT taxonomy meta_fields not showing in Wordpress REST API

I added a custom meta field to my cpt taxonomy with "{$taxonomy}_add_form_fields".
So far it is working fine (add, edit and save) but I cant find this field in the API /wp-json/wp/v2/rest_base.
Is this a filter issue or do i "ADD" this field to the API?
... This answers a slightly different question than the one above ...
You need to enable the REST API where you defined the taxonomy.
Just add 'show_in_rest_api' => true
Something like this:
<?php
add_action( 'init', 'create_book_tax' );
function create_book_tax() {
register_taxonomy(
'genre',
'book',
array(
'label' => __( 'Genre' ),
'rewrite' => array( 'slug' => 'genre' ),
'hierarchical' => true,
'show_in_rest_api' => true // <-- Do This!
)
);
}
?>
You register the meta field calling register_term_meta, observe that using show_in_rest key not only set to true, but at least with an schema description, it is available both in queries to get the data, and to get the schema of that endpoint with OPTIONS method.
register_term_meta('replica', 'nice_field', [
'type' => 'string',
'description' => 'a nice description',
'single' => true,
'show_in_rest' => [
'schema' => [
'type' => 'string',
'format' => 'url',
'context' => ['view', 'edit'],
'readonly' => true,
]
],
]);
Using the schema key its currently documented only for non scalar types, but it's valid for scalar values too.
I had a similar issue. The answers here seem to point to the way to expose the taxonomy itself via the REST API, but not the custom fields created via ${taxonomy}_add_form_fields.
After some more research, I concluded that one should extend the REST API to modify the responses and explicitly add these custom taxonomy fields.
So, in my case, this was the solution:
// Add a custom field to the taxonomy form
function my_add_extra_fields_func()
{
$tpl = '
<div class="form-field form-required">
<label for="link">Field Label</label>
<input type="text" name="link" id="link" />
<p>Some help text</p>
</div>
';
echo $tpl;
}
add_action('taxonomySlug_add_form_fields', 'my_add_extra_fields_func');
// Save the custom field to database in the options table
function my_save_extra_fields_func($term_id)
{
$term_item = get_term($term_id, 'taxonomySlug');
$term_slug = $term_item->slug;
$link = sanitize_text_field($_POST['link']);
update_option('taxonomySlug_link_' . $term_slug, $link);
}
add_action('create_taxonomySlug', 'my_save_extra_fields_func');
/**
* This is the part that addresses the question
* of making the custom field visible in the API
*/
// Expose the taxonomy custom field via REST API
add_action( 'rest_api_init', function () {
register_rest_field( 'taxonomySlug', 'extra_fields', array(
'get_callback' => function( $term_as_arr ) {
$term_slug = $term_as_arr['slug'];
$link = get_option('taxonomySlug_link_' . $term_slug);
return $link;
})
);
});
* taxonomySlug = the slug of my taxonomy

Update wordpress post from front-end (using acf)

I am making front end admin for users to add/edit their posts. I already made post add form and it works, but edit form doesnt work.
functions.php
function add_new_post( $post_id )
{
if( $post_id == 'new' ) {
// Create a new post
$post = array(
'post_title' => $_POST["fields"]['field_52c810cb44c7a'],
'post_category' => array(4),
'post_status' => 'draft',
'post_type' => 'post'
);
// insert the post
$post_id = wp_insert_post( $post );
return $post_id;
}
else {
return $post_id;
}
}add_filter('acf/pre_save_post' , 'add_new_post' );
index.php
<div id="updateform-<?php the_ID(); ?>" class="collapse">
<?php
echo get_the_ID();
$args = array(
'post_id' => get_the_ID(), // post id to get field groups from and save data to
'field_groups' => array(31), // this will find the field groups for this post (post ID's of the acf post objects)
'form' => true, // set this to false to prevent the <form> tag from being created
'form_attributes' => array( // attributes will be added to the form element
'id' => 'post',
'class' => '',
'action' => get_permalink( get_the_ID() ),
'method' => 'post',
),
'return' => add_query_arg( 'updated', 'true', get_permalink() ), // return url
'html_before_fields' => '', // html inside form before fields
'html_after_fields' => '', // html inside form after fields
'submit_value' => 'Update', // value for submit field
'updated_message' => 'Post updated.', // default updated message. Can be false to show no message
);
acf_form( $args );
?>
</div>
For saving posts you should use save_post not pre_save_post.
Basically pre_save_post is used for new posts.
Use this below add_filter('save_post' , 'add_new_post');
I created plugins for that:
Forms actions
https://wordpress.org/plugins/forms-actions/
Add actions to yours ACF forms.
ACF Frontend display
https://wordpress.org/plugins/acf-frontend-display/
Display your ACF form on frontend
If by some chance you happen to be using Elementor Page Builder, you can do this by installing Advanced Widgets for Elementor. It comes with an ACF Form widget that you can just drag & drop anywhere into your site and configure your form through the UI (no coding required).

Resources