I have created a custom checkout field for WooCommerce. I have also added the validation. But after clicking on place order, my custom fields also checked if it is validated or not. But, I want to check if my custom field is valid or not at the end. I mean, all other required fields will be check and after that my custom field will be checked.
Below is my code structure:
function otp_func($checkout) {
.............................
}
add_action( 'woocommerce_after_checkout_billing_form', 'otp_func', 10 );
add_action('woocommerce_checkout_process','my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
..........................
}
And below is my validation code which I want to run at the end if all the other fields validate successfully:
if (!$_POST['otp_field']) {
wc_add_notice( __( 'OTP field is blank' ), 'error' );
} else if ( $_POST['otp_field'] != $otp_verify_report ) {
wc_add_notice( __( 'Invalid OTP or OTP has been expired!' ), 'error' );
}
Use below code to validate new field.
Add Below code in theme functions.php
add_action( 'woocommerce_after_checkout_validation', 'wc_check_confirm_password_matches_checkout', 10, 2 );
function wc_check_confirm_password_matches_checkout( $posted ) {
$checkout = WC()->checkout;
if ( ! empty( $posted['otp_field'] ) ) {
wc_add_notice( __( 'OTP field is blank' ), 'error' );
} else if ( $posted['otp_field'] != $otp_verify_report ) {
wc_add_notice( __( 'Invalid OTP or OTP has been expired!' ), 'error' );
}
}
You can have a try with:
function customise_checkout_field_process()
{
if (!$_POST['the_customised_field_name']) wc_add_notice(__('the warning message') , 'error');
}
Related
I'm using WooCommerce to restrict a coupon to the user role "gold-member" which works fine but I'm trying to change the message displayed when an invalid user tries to use the coupon:
Sorry, coupon code "goldmember10" is not valid with your customer role.
My code
add_filter( 'woocommerce_coupon_error','coupon_error_message_change',10,3 );
function coupon_error_message_change($err, $err_code, $parm ) {
switch ( $err_code ) {
case 100:
$err = sprintf( __( 'Sorry, coupon code "%s" is not valid.', 'woocommerce' ), $parm->get_code() );
break;
}
return $err;
}
$err_code matches 100 per class-wc-coupon.php but the message does not get updated.
This should suffice:
function filter_woocommerce_coupon_error( $err, $err_code, $coupon ) {
// Compare
if ( intval( $err_code ) === WC_COUPON::E_WC_COUPON_INVALID_FILTERED ) {
// Message
$err = sprintf( __( 'Sorry, coupon code "%s" is not valid.', 'woocommerce' ), $coupon->get_code() );
} else {
$err = 'DEBUG INFORMATION, error code number = ' . intval( $err_code );
}
return $err;
}
add_filter( 'woocommerce_coupon_error', 'filter_woocommerce_coupon_error', 10, 3 );
What Woocommerce Does is...
When products are Sold Individually, and when the product already exists in the Cart and customer clicks on Add to Cart, Woocommerce shows Error Message "You cannot add another to your cart.....View Cart"
Instead of the above flow I want..
When customer clicks on Add to Cart and if the product already exists in the Cart then woocommerce should redirect to Checkout page straightway.
I think this can be achieved by editing few lines of code in class-wc-cart.php of Woocommerce Plugin.
The is given below:
// Force quantity to 1 if sold individually and check for existing item in cart
if ( $product_data->is_sold_individually() ) {
$quantity = apply_filters( 'woocommerce_add_to_cart_sold_individually_quantity', 1, $quantity, $product_id, $variation_id, $cart_item_data );
$in_cart_quantity = $cart_item_key ? $this->cart_contents[ $cart_item_key ]['quantity'] : 0;
if ( $in_cart_quantity > 0 ) {
throw new Exception( sprintf( '%s %s', wc_get_cart_url(), __( 'View Cart', 'woocommerce' ), sprintf( __( 'You cannot add another "%s" to your cart.', 'woocommerce' ), $product_data->get_title() ) ) );
}
}
I was just looking into how to do this myself. user1072884's answer is okay, however, it only works for one productID at a time. Not ideal if you have multiple products.
Here's a simplified solution that will work for all products.
Simply add the following code to your child theme functions.php and swap the placeholder text with your checkout page URL.
/** If multiple items are in the cart redirect to the checkout page instead of throwing an error **/
add_filter( 'woocommerce_add_to_cart_validation', 'check_cart' );
function check_cart( $cart_item_data ) {
global $woocommerce;
if ( $woocommerce->cart->cart_contents_count > 0 ) {
$direct_url = home_url( 'xyz' ); // Change the value of your actual redirect url.
wp_redirect( $direct_url );
exit();
}
}
Old thread, but maybe someone else will find this helpful.
Try this it will work:
add_filter( 'woocommerce_add_to_cart_sold_individually_quantity', 'vipcomment_change_quantity_to_zero', 10, 5 );
function vipcomment_change_quantity_to_zero( $one, $quantity, $product_id, $variation_id, $cart_item_data ) {
$your_product_id = 96;
if ( $product_id == $your_product_id ) {
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $in_cart ) {
return 0;
} else {
return $quantity;
}
} else {
return $quantity;
}
}
add_filter( 'woocommerce_add_to_cart_sold_individually_found_in_cart', 'vipcomment_is_product_exist_in_cart', 10, 5 );
function vipcomment_is_product_exist_in_cart( $exist, $product_id, $variation_id, $cart_item_data, $cart_id ) {
$your_product_id = 96;
if ( $product_id == $your_product_id ) {
return false;
} else {
return $exist;
}
}
Simplest way would be:
throw new Exception( sprintf( '%s %s',
wc_get_cart_url(), __( 'View cart', 'woocommerce' ),
header( "Location: https://www.example.com/cart/" ) ) );
instead of that error. Be advised: this will redirect the user to the cart page ( where the product should already be in place ).
I'm Italian (sorry for my english) and I'm not a programmer.
I need to insert in my checkout woocommerce site, a radio button with two options to answer this question: "Sei un privato cittadino, un'azienda o un libero professionista?".
These are the options:
1) Privato cittadino
2) Azienda o libero professionista
When users click on the first option, it has to show a required field: "codice fiscale". When users click on the second option, it has to show two required fields: "P.Iva" and "Ragione sociale". I've created the radio field with this code in form-billing.php:
<div class="woocommerce-billing-fields">
<?php if ( wc_ship_to_billing_address_only() && WC()->cart->needs_shipping() ) : ?>
<h3><?php _e( 'Billing & Shipping', 'woocommerce' ); ?></h3>
<?php else : ?>
<h3><?php _e( 'Billing Details', 'woocommerce' ); ?></h3>
<?
if($key=='billing_first_name')
{
?>
<p>Sei un privato cittadino, un'azienda o un libero professionista?</p>
<input type="radio" name="choice" value="privato_cittadino">Privato cittadino
<input type="radio" name="choice" value="azienda_professionista">Azienda o libero professionista<br>
<?
}
?>
<?php endif; ?>
It works properly, but now I don't know how can I create the required fields like I described.
Can you help me step by step? Please, consider I'm not a programmer.
To answer the question, it will need to be done in 4 steps.
Add 4 custom fields to the woocommerce checkout page. The way you have done it is not best practice and should be done through use of actions/filters.
Validate the data when the request is made to the back-end, this is to make sure the user actually selected and entered what is required.
Save the data to the order as post meta so it can be accessed later.
Implement javascript toggle feature so that based on what the user selects for the first question, the related fields are then shown.
Adding custom fields to woocommerce checkout
You will need to find a suitable action for where you would like to add the fields. I would recommend using the action woocommerce_after_checkout_billing_form as it will display fields after all the personal/billing information.
if( !function_exists( 'custom_checkout_question_field' ) ) {
/**
* Add custom question field after the billing form fields
*
* #param Integer $order_id New order id
*/
function custom_checkout_question_field( $checkout ) {
echo "<div class='custom-question-field-wrapper custom-question-1'>";
echo sprintf( '<p>%s</p>', __( "Sei un privato cittadino, un'azienda o un libero professionista?" ) );
woocommerce_form_field( 'custom_question_field', array(
'type' => 'radio',
'required' => true,
'class' => array('custom-question-field', 'form-row-wide'),
'options' => array(
'privato_cittadino' => 'Privato cittadino',
'azienda_professionista' => 'Azienda o libero professionista',
),
), $checkout->get_value( 'custom_question_field' ) );
woocommerce_form_field( 'custom_question_text_codice_fiscale', array(
'type' => 'text',
'label' => 'Codice Fiscale',
'required' => true,
'class' => array('custom-question-codice-fiscale-field', 'form-row-wide'),
), $checkout->get_value( 'custom_question_text_codice_fiscale' ) );
woocommerce_form_field( 'custom_question_text_p_iva', array(
'type' => 'text',
'label' => 'P.Iva',
'required' => true,
'class' => array('custom-question-p-iva-field', 'form-row-wide'),
), $checkout->get_value( 'custom_question_text_p_iva' ) );
woocommerce_form_field( 'custom_question_text_ragione_sociale', array(
'type' => 'text',
'label' => 'Ragione sociale',
'required' => true,
'class' => array('custom-question-ragione-sociale-field', 'form-row-wide'),
), $checkout->get_value( 'custom_question_text_ragione_sociale' ) );
echo "</div>";
}
add_action( 'woocommerce_after_checkout_billing_form', 'custom_checkout_question_field' );
}
Javascript front-end toggle
You will need to add custom javascript in order to toggle the 3 additional fields depending on the question. I have created a php function which will output a html script tag with some javascript. This is then attached to the wp_footer action.
This is not recommended method and you should really separate it into a new file js and enqueue the file when needed.
See: https://codex.wordpress.org/Plugin_API/Action_Reference/wp_enqueue_scripts
if( !function_exists( 'custom_question_conditional_javascript' ) ) {
function custom_question_conditional_javascript() {
?>
<script type="text/javascript">
(function() {
// Check if jquery exists
if(!window.jQuery) {
return;
};
var $ = window.jQuery;
$(document).ready(function() {
var questionField = $('.custom-question-field'),
codiceFiscaleField = $('.custom-question-codice-fiscale-field'),
pIvaField = $('.custom-question-p-iva-field'),
ragioneSocialeField = $('.custom-question-ragione-sociale-field ');
// Check that all fields exist
if(
!questionField.length ||
!codiceFiscaleField.length ||
!pIvaField.length ||
!ragioneSocialeField.length
) {
return;
}
function toggleVisibleFields() {
var selectedAnswer = questionField.find('input:checked').val();
if(selectedAnswer === 'privato_cittadino') {
codiceFiscaleField.show();
pIvaField.hide();
ragioneSocialeField.hide();
} else if(selectedAnswer === 'azienda_professionista') {
codiceFiscaleField.hide();
pIvaField.show();
ragioneSocialeField.show();
} else {
codiceFiscaleField.hide();
pIvaField.hide();
ragioneSocialeField.hide();
}
}
$(document).on('change', 'input[name=custom_question_field]', toggleVisibleFields);
$(document).on('updated_checkout', toggleVisibleFields);
toggleVisibleFields();
});
})();
</script>
<?php
}
add_action( 'wp_footer', 'custom_question_conditional_javascript', 1000 );
}
Getting fields from submitted post request
You will need to get the data from php $_POST array and also sanitise it to prevent sql injection or other malicious code. I have created a helper function which will grab all the fields by keys provided in an array and sanitise them using wordpress sanitize_text_field helper function.
This helper can then be used when validating and also adding post meta.
if( !function_exists( 'custom_checkout_question_get_field_values' ) ) {
/**
* Get all form field values based on user submitted post data
*
* #return Array Key/value pair of field values based on $_POST data
*/
function custom_checkout_question_get_field_values() {
$fields = [
'custom_question_field' => '',
'custom_question_text_codice_fiscale' => '',
'custom_question_text_p_iva' => '',
'custom_question_text_ragione_sociale' => '',
];
foreach( $fields as $field_name => $value ) {
if( !empty( $_POST[ $field_name ] ) ) {
$fields[ $field_name ] = sanitize_text_field( $_POST[ $field_name ] );
} else {
unset( $fields[ $field_name ] );
}
}
return $fields;
}
}
Validating fields on the back-end
Validation is important because front-end cannot be trusted, it is very easy for users to modify required fields on the front-end. You can use Woocommerce woocommerce_checkout_process action in order to validate the fields and add error messages if it does not meet what is required.
if( !function_exists( 'custom_checkout_question_field_validate' ) ) {
/**
* Custom woocommerce field validation to prevent user for completing checkout
*
* #param Integer $order_id New order id
*/
function custom_checkout_question_field_validate() {
$field_values = custom_checkout_question_get_field_values();
if ( empty( $field_values['custom_question_field'] ) ) {
wc_add_notice( 'Please select an answer for the question.', 'error' );
}
if (
$field_values['custom_question_field'] === 'privato_cittadino' &&
empty( $field_values['custom_question_text_codice_fiscale'] )
) {
wc_add_notice( 'Please enter codice fiscale.', 'error' );
}
if (
$field_values['custom_question_field'] === 'azienda_professionista' &&
empty( $field_values['custom_question_text_p_iva'] )
) {
wc_add_notice( 'Please enter p iva.', 'error' );
}
if (
$field_values['custom_question_field'] === 'azienda_professionista' &&
empty( $field_values['custom_question_text_ragione_sociale'] )
) {
wc_add_notice( 'Please enter ragione sociale.', 'error' );
}
}
add_action( 'woocommerce_checkout_process', 'custom_checkout_question_field_validate' );
}
Saving custom post meta to the order
You can use the woocommerce woocommerce_checkout_update_order_meta action in order to save additional post meta to the order post type. Here we will use the helper function custom_checkout_question_get_field_values created above to get all fields from php $_POST array and also sanitize them before saving each one to the post meta.
if( !function_exists( 'custom_checkout_question_field_save' ) ) {
/**
* Update order post meta based on submitted form values
*
* #param Integer $order_id New order id
*/
function custom_checkout_question_field_save( $order_id ) {
$field_values = custom_checkout_question_get_field_values();
foreach( $field_values as $field_name => $value ) {
if( !empty( $field_values[ $field_name ] ) ) {
update_post_meta( $order_id, $field_name, $value );
}
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_question_field_save' );
}
is it posible to make woo 'order_comments' field required - and show message If the field is not filled
I have tried the following code but I can not get it to work.
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['my_field_name'] )
wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}
Hope there is someone who can help
Add below code in "functions.php" file of an active child theme.
// Make order notes required
add_filter( 'woocommerce_checkout_fields' , 'wc_override_checkout_fields' );
function wc_override_checkout_fields( $fields ) {
$fields['order']['order_comments']['required'] = true;
return $fields;
}
Reference https://gist.github.com/MindyPostoff/cbf34de936445972737f
Change the action from 'woocommerce_checkout_process' to 'woocommerce_after_checkout_validation'.
add_action('woocommerce_after_checkout_validation', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['order_comments'] )
wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}
I am working on a wordpress project and I want to add the bulk action on my custom post.
I have used Custom Post Type UI plugin for custom post and Advanced Custom Fields plugin for custom fields.
Please suggest me any code or plugin to add bulk action for my custom posts.
Thanks,
Aniket.
Since WordPress 4.7 (released December 2016) it is possible to add custom bulk actions without using JavaScript.
//Hooks
add_action( 'current_screen', 'my_bulk_hooks' );
function my_bulk_hooks() {
if( current_user_can( 'administrator' ) ) {
add_filter( 'bulk_actions-edit-post', 'register_my_bulk_actions' );
add_filter( 'handle_bulk_actions-edit-post', 'my_bulk_action_handler', 10, 3 );
add_action( 'admin_notices', 'my_bulk_action_admin_notice' );
}
}
//Register
function register_my_bulk_actions($bulk_actions) {
$bulk_actions['email_to_eric'] = __( 'Email to Eric', 'text_domain');
return $bulk_actions;
}
//Handle
function my_bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
if ( $doaction !== 'email_to_eric' ) {
return $redirect_to;
}
foreach ( $post_ids as $post_id ) {
// Perform action for each post.
}
$redirect_to = add_query_arg( 'bulk_emailed_posts', count( $post_ids ), $redirect_to );
return $redirect_to;
}
//Notices
function my_bulk_action_admin_notice() {
if ( ! empty( $_REQUEST['bulk_emailed_posts'] ) ) {
$emailed_count = intval( $_REQUEST['bulk_emailed_posts'] );
printf( '<div id="message" class="updated fade">' .
_n( 'Emailed %s post to Eric.',
'Emailed %s posts to Eric.',
$emailed_count,
'text_domain'
) . '</div>', $emailed_count );
}
}
Note.1: You must use bulk_actions filters when WP_Screen object is defined.That's why I used current_screen action in line 2.
Note.2: if you want to add bulk action to custom page like woocommerce products page just change screen id in line 5 & 6. Ex:
add_filter( 'bulk_actions-edit-product', 'register_my_bulk_actions' );
add_filter( 'handle_bulk_actions-edit-product', 'my_bulk_action_handler', 10, 3 );
More information :
Using Custom Bulk Actions
https://make.wordpress.org/core/2016/10/04/custom-bulk-actions/
use "register_post_type" of WordPress function, It easier than the additional plugins
Reference: https://codex.wordpress.org/Function_Reference/register_post_type