Woocommerce - Validation on cart page - wordpress

I have a custom filed for specific shipping methods (see screenshot).
Is there a hook/action to validate this field before proceeding the checkout. When I set the field to required the validation will fire at the checkout page but I want it at the cart page.
Validation:
//Validate the custom selection field
add_action('woocommerce_checkout_process', 'carrier_company_checkout_validation');
function carrier_company_checkout_validation() {
Load settings and convert them in variables
extract( custom_field_settings() );
if( isset( $_POST[$field_id] ) && empty( $_POST[$field_id] ) )
wc_add_notice(
sprintf( __("Please select a %s as it is a required field.","woocommerce"),
'<strong>' . $label_name . '</strong>'
), "error" );
}
** UPDATE: **
like #LoicTheAztec mentioned here the complete code.
Everything is working fine. The custom input value from cart will be shown on checkout and saved in the DB after order confirmation. But I don't know where I have to put the validation on the cart page when the custom input is empty because everything on cart is on ajax.
// ##########################################
// Add custom fields to a specific selected shipping method
// ##########################################
// Custom function that handle your settings
function delivery_date_settings(){
return array(
'field_id' => 'delivery_date', // Field Id
'field_type' => 'text', // Field type
'field_label' => 'label text', // Leave empty value if the first option has a text (see below).
'label_name' => __("Lieferdatum","woocommerce"), // for validation and as meta key for orders
);
}
// Display the custom checkout field
add_action( 'woocommerce_after_shipping_rate', 'carrier_company_custom_select_field', 20, 2 );
function carrier_company_custom_select_field( $method, $index ) {
if( $method->id == 'flat_rate:2' || $method->id == 'free_shipping:1') {
extract( delivery_date_settings() ); // Load settings and convert them in variables
$chosen = WC()->session->get('chosen_shipping_methods'); // The chosen methods
$value = WC()->session->get($field_id);
$value = WC()->session->__isset($field_id) ? $value : WC()->checkout->get_value('_'.$field_id);
$options = array(); // Initializing
$chosen_method_id = WC()->session->chosen_shipping_methods[ $index ];
if($chosen_method_id == 'flat_rate:2' || $method->id == 'free_shipping:1' ){
echo '<div class="custom-date-field">';
woocommerce_form_field( $field_id, array(
'type' => $field_type,
'label' => $field_label, // Not required if the first option has a text.
'class' => array('form-row-wide datepicker ' . $field_id . '-' . $field_type ),
'required' => false,
), $value );
echo '</div>';
// Jquery: Enable the Datepicker
?>
<script language="javascript">
jQuery( function($){
$('.datepicker input').datepicker({
dateFormat: 'dd.mm.yy', // ISO formatting date
});
});
</script>
<?php
}
}
}
// jQuery code (client side) - Ajax sender
add_action( 'wp_footer', 'carrier_company_script_js' );
function carrier_company_script_js() {
// Only cart & checkout pages
if( is_cart() || ( is_checkout() && ! is_wc_endpoint_url() ) ):
// Load settings and convert them in variables
extract( lieferdatum_settings() );
$js_variable = is_cart() ? 'wc_cart_params' : 'wc_checkout_params';
// jQuery Ajax code
?>
<script type="text/javascript">
jQuery( function($){
if (typeof <?php echo $js_variable; ?> === 'undefined')
return false;
$(document.body).on( 'change', 'input#<?php echo $field_id; ?>', function(){
var value = $(this).val();
$.ajax({
type: 'POST',
url: <?php echo $js_variable; ?>.ajax_url,
data: {
'action': 'delivery_date',
'value': value
},
success: function (result) {
console.log(result); // Only for testing (to be removed)
}
});
});
});
</script>
<?php
endif;
}
// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_delivery_date', 'set_carrier_company_name' );
add_action( 'wp_ajax_nopriv_delivery_date', 'set_carrier_company_name' );
function set_carrier_company_name() {
if ( isset($_POST['value']) ){
// Load settings and convert them in variables
extract( delivery_date_settings() );
if( empty($_POST['value']) ) {
$value = 0;
$label = 'Empty';
} else {
$value = $label = esc_attr( $_POST['value'] );
}
// Update session variable
WC()->session->set( $field_id, $value );
// Send back the data to javascript (json encoded)
echo $label;
die();
}
}
// Save custom field as order meta data
add_action( 'woocommerce_checkout_create_order', 'save_carrier_company_as_order_meta', 30, 1 );
function save_carrier_company_as_order_meta( $order ) {
// Load settings and convert them in variables
extract( delivery_date_settings() );
if( isset( $_POST[$field_id] ) && ! empty( $_POST[$field_id] ) ) {
$order->update_meta_data( '_'.$field_id, esc_attr($_POST[$field_id]) );
WC()->session->__unset( $field_id ); // remove session variable
}
}
// Display custom field in admin order pages
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'admin_order_display_carrier_company', 30, 1 );
function admin_order_display_carrier_company( $order ) {
// Load settings and convert them in variables
extract( delivery_date_settings() );
$carrier = $order->get_meta( '_'.$field_id ); // Get carrier company
if( ! empty($carrier) ) {
// Display
echo '<p><strong>' . $label_name . '</strong>: ' . $carrier . '</p>';
}
}
// Display carrier company after shipping line everywhere (orders and emails)
add_filter( 'woocommerce_get_order_item_totals', 'display_carrier_company_on_order_item_totals', 1000, 3 );
function display_carrier_company_on_order_item_totals( $total_rows, $order, $tax_display ){
// Load settings and convert them in variables
extract( delivery_date_settings() );
$carrier = $order->get_meta( '_'.$field_id ); // Get carrier company
if( ! empty($carrier) ) {
$new_total_rows = [];
// Loop through order total rows
foreach( $total_rows as $key => $values ) {
$new_total_rows[$key] = $values;
// Inserting the carrier company under shipping method
if( $key === 'shipping' ) {
$new_total_rows[$field_id] = array(
'label' => $label_name,
'value' => $carrier,
);
}
}
return $new_total_rows;
}
return $total_rows;
}

I think the hook you're looking for is woocommerce_check_cart_items, that's the one that validates the cart items before proceeding to checkout.
I'm not 100% sure whether you'll be able to get the field in the same way using $_POST but it's worth a go.

Related

How can get the checkout field value and hidden order button in woocommerce?

I have payment needed to wait for JS callback token, so on the checkout page, the flow will have the customer check the token button, then click and get the token will apply to the custom field,
in the end, if the custom field is not empty show the order button.
custom field
function techiepress_payleo_description_fields( $description, $payment_id ) {
if( 'payleos' !== $payment_id) {
return $description;
};
// $json = json_encode(WC()->cart);
ob_start();
echo '<div id="Payment">'; // it will create get token button
echo '</div>';
woocommerce_form_field( 'payment_number', array(
'type' => 'text',
'label' => __("credit card", "payleo_payment_plus"),
'required' => true,
),'');
$description .= ob_get_clean();
return $description;
}
hidden order button
add_filter('woocommerce_order_button_html', 'remove_place_order_button_for_specific_payments' );
function remove_place_order_button_for_specific_payments( $button ) {
// HERE define your targeted payment(s) method(s) in the array
$targeted_payments_methods = array('payleos');
$chosen_payment_method = WC()->session->get('chosen_payment_method'); // The chosen payment
// For matched payment(s) method(s), we remove place order button (on checkout page)
if( in_array( $chosen_payment_method, $targeted_payments_methods ) && ! is_wc_endpoint_url() ) {
$button = '';
}
return $button;
}
// jQuery - Update checkout on payment method change
add_action( 'wp_footer', 'custom_checkout_jquery_script' );
function custom_checkout_jquery_script() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?>
<script type="text/javascript">
jQuery( function($){
$('form.checkout').on('change', 'input[name="payment_method"]', function(){
$(document.body).trigger('update_checkout');
});
});
</script>
<?php
endif;
}
I would like to know how can show the place order button when the custom field has value?

Add a WooCommerce checkout checkbox field that enable a discount based on product quantity

Based on Add a checkout checkbox field that enable a percentage fee in Woocommerce answer code, I've got a custom checkbox on which I need to offer discount to customers.
I'm trying to apply the custom discount of say $0.03 x product quantity e.g.
If quantity is 50 then the discount would be 50 x $0.03 = $1.5
Right now, it's deducting $0.03 from the Cart Total. Can anyone help me with achieving the required results?
Here is my code attempt:
// Add a custom checkbox fields after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){
// Add a custom checkbox field
woocommerce_form_field( 'discount30', array(
'type' => 'checkbox',
'label' => __(' Senior'),
'class' => array( 'form-row-wide' ),
), '' );
}
// Remove "(optional)" label on "Installement checkbox" field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'discount30' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) .
')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=discount30]', function(e){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set('enable_fee', ($_POST['enable_fee'] ? true : false) );
}
die();
}
// Add a custom 3 Cents Discount
add_action( 'woocommerce_cart_calculate_fees', 'custom_discount', 20, 1 );
function custom_discount( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
$discount = -0.03;
if( WC()->session->get('enable_fee') )
$cart->add_fee( __( 'Discount', 'woocommerce'), ( $discount ) );
}
To determine the discount based on the number of items in the cart, you can use WC()->cart->get_cart_contents_count();
Which then can be applied in the woocommerce_cart_calculate_fees action hook.
So you get:
// Add a custom checkbox fields after billing fields
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Add a custom checkbox field
woocommerce_form_field( 'discount30', array(
'type' => 'checkbox',
'label' => __( ' Senior', 'woocommerce' ),
'class' => array( 'form-row-wide' ),
), '' );
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
// Remove "(optional)" label on "discount30" field
function filter_woocommerce_form_field( $field, $key, $args, $value ) {
// Only on checkout page
if ( $key === 'discount30' && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
add_filter( 'woocommerce_form_field' , 'filter_woocommerce_form_field', 10, 4 );
// jQuery - Ajax script
function action_wp_footer() {
// Only on Checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :
if ( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if ( typeof wc_checkout_params === 'undefined' )
return false;
$( 'form.checkout' ).on( 'change', 'input[name=discount30]', function(e) {
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );
// Get Ajax request and saving to WC session
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set( 'enable_fee', ( $_POST['enable_fee'] ? true : false ) );
}
die();
}
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
// Add a custom 3 Cents Discount
function action_woocommerce_cart_calculate_fees( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
// Get number of items in the cart.
$items_in_cart = $cart->get_cart_contents_count();
// Calculate
$discount = 0.03 * $items_in_cart;
// Apply discount
if ( WC()->session->get('enable_fee') ) {
$cart->add_fee( __( 'Discount', 'woocommerce' ), -$discount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
Note: to get the number of products in cart opposite the number of items in cart
Change
// Get number of items in the cart.
$items_in_cart = $cart->get_cart_contents_count();
// Calculate
$discount = 0.03 * $items_in_cart;
To
// Products in cart
$products_in_cart = count( $cart->get_cart() );
// Calculate
$discount = 0.03 * $products_in_cart;

Multiple select product using select2 for wordpress plugin option page

I am trying to implement multiple select product using select2 . the list come up using getproductsearch this ajax action i did earlier but i failed to save it. I did this feature before for post-meta and product-category but failed for plugin option page. I am not sure what i am doing wrong.
please help.
class FeatureSale {
private $feature_sale_options;
public function __construct() {
add_action( 'admin_menu', array( $this, 'feature_sale_add_plugin_page' ) );
add_action( 'admin_init', array( $this, 'feature_sale_page_init' ) );
}
public function feature_sale_add_plugin_page() {
add_submenu_page(
'exclutips-settings',
'Feature & Sale', // page_title
'Feature & Sale', // menu_title
'manage_options', // capability
'feature-sale', // menu_slug
array( $this, 'feature_sale_create_admin_page' ) // function
);
}
public function feature_sale_create_admin_page() {
$this->feature_sale_options = get_option( 'feature_sale_option_name' ); ?>
<div class="wrap">
<div class="catbox-area-admin" style="width: 500px;background: #fff;padding: 27px 50px;">
<h2>Feature & Sale</h2>
<p></p>
<?php settings_errors(); ?>
<form method="post" action="options.php">
<?php
settings_fields( 'feature_sale_option_group' );
do_settings_sections( 'feature-sale-admin' );
submit_button();
?>
</form>
</div>
</div>
<?php }
public function feature_sale_page_init() {
register_setting(
'feature_sale_option_group', // option_group
'feature_sale_option_name', // option_name
array( $this, 'feature_sale_sanitize' ) // sanitize_callback
);
add_settings_section(
'feature_sale_setting_section', // id
'', // title
array( $this, 'feature_sale_section_info' ), // callback
'feature-sale-admin' // page
);
add_settings_field(
'vpm_sale_product', // id
'VPM Sale Product', // title
array( $this, 'vpm_sale_product_callback' ), // callback
'feature-sale-admin', // page
'feature_sale_setting_section' // section
);
add_settings_field(
'vpm_featured_product', // id
'VPM Featured Product', // title
array( $this, 'vpm_featured_product_callback' ), // callback
'feature-sale-admin', // page
'feature_sale_setting_section' // section
);
}
public function feature_sale_sanitize($input) {
$sanitary_values = array();
if ( isset( $input['vpm_sale_product'] ) ) {
$sanitary_values['vpm_sale_product'] = $input['vpm_sale_product'];
}
if ( isset( $input['vpm_featured_product'] ) ) {
$sanitary_values['vpm_featured_product'] = $input['vpm_featured_product'];
}
return $sanitary_values;
}
public function feature_sale_section_info() {
}
//Output the HTML for the metabox.
public function vpm_sale_product_callback() {
global $post;
// Nonce field to validate form request came from current site
wp_nonce_field( basename( __FILE__ ), 'vpm_sale_product_nonce' );
$html = '';
// always array because we have added [] to our <select> name attribute
$feature_sale_options = get_option( 'feature_sale_option_name' ); // Array of All Options
$vpm_sale_product = $feature_sale_options['vpm_sale_product'];
$html .= '<p><select id="vpm_sale_product" name="vpm_sale_product[]" multiple="multiple" style="width:99%;max-width:25em;">';
if( $vpm_sale_product ) {
foreach( $vpm_sale_product as $post_id ) {
$title = get_the_title( $post_id );
// if the post title is too long, truncate it and add "..." at the end
$title = ( mb_strlen( $title ) > 50 ) ? mb_substr( $title, 0, 49 ) . '...' : $title;
$html .= '<option value="' . $post_id . '" selected="selected">' . $title . '</option>';
}
}
$html .= '</select></p>';
echo $html;
//==========================================
}
//* Output the HTML for the metabox.
public function vpm_featured_product_callback() {
global $post;
// Nonce field to validate form request came from current site
wp_nonce_field( basename( __FILE__ ), 'vpm_featured_product_nonce' );
$html = '';
// always array because we have added [] to our <select> name attribute
$feature_sale_options = get_option( 'feature_sale_option_name' ); // Array of All Options
$vpm_featured_product = $feature_sale_options['vpm_featured_product'];
$html .= '<p><select id="vpm_featured_product" name="vpm_featured_product[]" multiple="multiple" style="width:99%;max-width:25em;">';
if( $vpm_featured_product ) {
foreach( $vpm_featured_product as $post_id ) {
$title = get_the_title( $post_id );
// if the post title is too long, truncate it and add "..." at the end
$title = ( mb_strlen( $title ) > 50 ) ? mb_substr( $title, 0, 49 ) . '...' : $title;
$html .= '<option value="' . $post_id . '" selected="selected">' . $title . '</option>';
}
}
$html .= '</select></p>';
echo $html;
echo $vpm_featured_product;
//==========================================
?>
<script>
(function ($) {
'use strict';
$(function () {
//--------------------------------------------------------------------------
// multiple select with AJAX search
$('#vpm_featured_product,#vpm_sale_product').select2({
ajax: {
url: ajaxurl, // AJAX URL is predefined in WordPress admin
dataType: 'json',
delay: 250, // delay in ms while typing when to perform a AJAX search
data: function (params) {
return {
q: params.term, // search query
action: 'getproductsearch' // AJAX action for admin-ajax.php
};
},
processResults: function( data ) {
var options = [];
if ( data ) {
// data is the array of arrays, and each of them contains ID and the Label of the option
$.each( data, function( index, text ) { // do not forget that "index" is just auto incremented value
options.push( { id: text[0], text: text[1] } );
});
}
return {
results: options
};
},
cache: true
},
minimumInputLength: 3 // the minimum of symbols to input before perform a search
});
//----------------------------------------------------------------------------------------
});
})(jQuery);
</script>
<?php
}
}
if ( is_admin() )
$feature_sale = new FeatureSale();
The problem is that these select tags are not using the correct name value:
<select id="vpm_sale_product" name="vpm_sale_product[]"...>
<select id="vpm_featured_product" name="vpm_featured_product[]"...>
And the proper name values are: (based on your register_setting() call)
<select id="vpm_sale_product" name="feature_sale_option_name[vpm_sale_product][]"...>
<select id="vpm_featured_product" name="feature_sale_option_name[vpm_featured_product][]"...>
And although after correcting the above issue, the form data would be saved properly, the fifth parameter (i.e. the menu/page slug) passed to add_submenu_page() should match the fourth parameter passed to add_settings_section() and add_settings_field(), and also the one passed to do_settings_sections(). In your add_submenu_page() call, the menu/page slug is feature-sale, but with the other three functions, you set it to feature-sale-admin.
And using wp_nonce_field() is recommended, but in your case, it's not necessary since you're submitting to wp-admin/options.php. Unless of course, you want to check that prior to WordPress saving the options. But even so, I believe one nonce field is good. :)

Add input field to every item in cart

I am trying to add a new field on my cart.php file.
I actually want to insert a URL field, so user can set a URL for each order item.
I tried to use a code from another post here but I can't get it to work.
The first and the second functions are working but when it comes to the third one, 'woocommerce_get_item_data' the $cart_item['url'] doesn't contain anything even if I add something in the field and I press Update Cart.
$cart_totals[ $cart_item_key ]['url'] from the first function is outputting the right value when the page load.
I don't know what to do now, thanks for any help.
Here is the code
Add the field
cart/cart.php
<td class="product-url">
<?php
$html = sprintf( '<div class="url"><input type="text" name="cart[%s][url]" value="%s" size="4" title="Url" class="input-text url text" /></div>', $cart_item_key, esc_attr( $values['url'] ) );
echo $html;
?>
</td>
functions.php
// get from session your URL variable and add it to item
add_filter('woocommerce_get_cart_item_from_session', 'cart_item_from_session', 99, 3);
function cart_item_from_session( $data, $values, $key ) {
$data['url'] = isset( $values['url'] ) ? $values['url'] : '';
return $data;
}
// this one does the same as woocommerce_update_cart_action() in plugins\woocommerce\woocommerce-functions.php
// but with your URL variable
// this might not be the best way but it works
add_action( 'init', 'update_cart_action', 9);
function update_cart_action() {
global $woocommerce;
if ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) ) {
$cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if ( isset( $cart_totals[ $cart_item_key ]['url'] ) ) {
$woocommerce->cart->cart_contents[ $cart_item_key ]['url'] = $cart_totals[ $cart_item_key ]['url'];
}
}
}
}
}
// this is in Order summary. It show Url variable under product name. Same place where Variations are shown.
add_filter( 'woocommerce_get_item_data', 'item_data', 10, 2 );
function item_data( $data, $cart_item ) {
if ( isset( $cart_item['url'] ) ) {
$data['url'] = array('name' => 'Url', 'value' => $cart_item['url']);
}
return $data;
}
// this adds Url as meta in Order for item
add_action ('woocommerce_add_order_item_meta', 'add_item_meta', 10, 2);
function add_item_meta( $item_id, $values ) {
woocommerce_add_order_item_meta( $item_id, 'Url', $values['url'] );
}
Add a textarea field to a WooCommerce cart item
First, we just need to add the textarea field. We use the woocommerce_after_cart_item_name hook so our textarea will appear after the product name.
<?php
/**
* Add a text field to each cart item
*/
function prefix_after_cart_item_name( $cart_item, $cart_item_key ) {
$notes = isset( $cart_item['notes'] ) ? $cart_item['notes'] : '';
printf(
'<div><textarea class="%s" id="cart_notes_%s" data-cart-id="%s">%s</textarea></div>',
'prefix-cart-notes',
$cart_item_key,
$cart_item_key,
$notes
);
}
add_action( 'woocommerce_after_cart_item_name', 'prefix_after_cart_item_name', 10, 2 );
/**
* Enqueue our JS file
*/
function prefix_enqueue_scripts() {
wp_register_script( 'prefix-script', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'update-cart-item-ajax.js', array( 'jquery-blockui' ), time(), true );
wp_localize_script(
'prefix-script',
'prefix_vars',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' )
)
);
wp_enqueue_script( 'prefix-script' );
}
add_action( 'wp_enqueue_scripts', 'prefix_enqueue_scripts' );
´´´
At the moment, the user will be able to enter text into the field but the text won’t save. We are going to use some AJAX to save the text.
The code above not only adds the textarea to the cart item, it also enqueues a JavaScript file ready for our AJAX.
It’s assumed that you’re using the code on this page to create a new plugin. If so, you should create a new JS file with the code below and place the file in the root directory of your plugin.
However, if you’ve added the PHP above to your theme functions.php or as a snippet on your site, you’ll need to change the location of the JS file by updating line 21 of the snippet above to identify the location of the JS file.
´´´
(function($){
$(document).ready(function(){
$('.prefix-cart-notes').on('change keyup paste',function(){
$('.cart_totals').block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
var cart_id = $(this).data('cart-id');
$.ajax(
{
type: 'POST',
url: prefix_vars.ajaxurl,
data: {
action: 'prefix_update_cart_notes',
security: $('#woocommerce-cart-nonce').val(),
notes: $('#cart_notes_' + cart_id).val(),
cart_id: cart_id
},
success: function( response ) {
$('.cart_totals').unblock();
}
}
)
});
});
})(jQuery);
´´´
Now, when the user types anything, the contents of the text field get sent back to the server ready to be saved as meta data to the cart item.
´´´
<?php
/**
* Update cart item notes
*/
function prefix_update_cart_notes() {
// Do a nonce check
if( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'woocommerce-cart' ) ) {
wp_send_json( array( 'nonce_fail' => 1 ) );
exit;
}
// Save the notes to the cart meta
$cart = WC()->cart->cart_contents;
$cart_id = $_POST['cart_id'];
$notes = $_POST['notes'];
$cart_item = $cart[$cart_id];
$cart_item['notes'] = $notes;
WC()->cart->cart_contents[$cart_id] = $cart_item;
WC()->cart->set_session();
wp_send_json( array( 'success' => 1 ) );
exit;
}
add_action( 'wp_ajax_prefix_update_cart_notes', 'prefix_update_cart_notes' );
function prefix_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
foreach( $item as $cart_item_key=>$cart_item ) {
if( isset( $cart_item['notes'] ) ) {
$item->add_meta_data( 'notes', $cart_item['notes'], true );
}
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'prefix_checkout_create_order_line_item', 10, 4 );
´´´
The prefix_update_cart_notes function does a security check using the WooCommerce cart nonce then saves the content of the textarea as meta data in the cart item. You can check out this article for more information about updating cart meta for items that have already been added to the cart.
Add the custom text to the order meta
Finally, we want to pass our meta data to the order so that we can use it after the customer has checked out. The prefix_checkout_create_order_line_item function takes care of that, iterating through each item and saving notes when it finds them.
https://pluginrepublic.com/how-to-add-an-input-field-to-woocommerce-cart-items/

Wordpress custom metabox input value with AJAX

I am using Wordpress 3.5, I have a custom post (sp_product) with a metabox and some input field. One of those input (sp_title).
I want to Search by the custom post title name by typing in my input (sp_title) field and when i press add button (that also in my custom meta box), It will find that post by that Title name and bring some post meta data into this Meta box and show into other field.
Here in this picture (Example)
Search
Click Button
Get some value by AJAX from a custom post.
Please give me a example code (just simple)
I will search a simple custom post Title,
Click a button
Get the Title of that post (that i search or match) with any other post meta value, By AJAX (jQuery-AJAX).
Please Help me.
I was able to find the lead because one of my plugins uses something similar to Re-attach images.
So, the relevant Javascript function is findPosts.open('action','find_posts').
It doesn't seem well documented, and I could only found two articles about it:
Find Posts Dialog Box
Using Built-in Post Finder in Plugins
Tried to implement both code samples, the modal window opens but dumps a -1 error. And that's because the Ajax call is not passing the check_ajax_referer in the function wp_ajax_find_posts.
So, the following works and it's based on the second article. But it has a security breach that has to be tackled, which is wp_nonce_field --> check_ajax_referer. It is indicated in the code comments.
To open the Post Selector, double click the text field.
The jQuery Select needs to be worked out.
Plugin file
add_action( 'load-post.php', 'enqueue_scripts_so_14416409' );
add_action( 'add_meta_boxes', 'add_custom_box_so_14416409' );
add_action( 'wp_ajax_find_posts', 'replace_default_ajax_so_14416409', 1 );
/* Scripts */
function enqueue_scripts_so_14416409() {
# Enqueue scripts
wp_enqueue_script( 'open-posts-scripts', plugins_url('open-posts.js', __FILE__), array('media', 'wp-ajax-response'), '0.1', true );
# Add the finder dialog box
add_action( 'admin_footer', 'find_posts_div', 99 );
}
/* Meta box create */
function add_custom_box_so_14416409()
{
add_meta_box(
'sectionid_so_14416409',
__( 'Select a Post' ),
'inner_custom_box_so_14416409',
'post'
);
}
/* Meta box content */
function inner_custom_box_so_14416409( $post )
{
?>
<form id="emc2pdc_form" method="post" action="">
<?php wp_nonce_field( 'find-posts', '_ajax_nonce', false); ?>
<input type="text" name="kc-find-post" id="kc-find-post" class="kc-find-post">
</form>
<?php
}
/* Ajax replacement - Verbatim copy from wp_ajax_find_posts() */
function replace_default_ajax_so_14416409()
{
global $wpdb;
// SECURITY BREACH
// check_ajax_referer( '_ajax_nonce' );
$post_types = get_post_types( array( 'public' => true ), 'objects' );
unset( $post_types['attachment'] );
$s = stripslashes( $_POST['ps'] );
$searchand = $search = '';
$args = array(
'post_type' => array_keys( $post_types ),
'post_status' => 'any',
'posts_per_page' => 50,
);
if ( '' !== $s )
$args['s'] = $s;
$posts = get_posts( $args );
if ( ! $posts )
wp_die( __('No items found.') );
$html = '<table class="widefat" cellspacing="0"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th class="no-break">'.__('Type').'</th><th class="no-break">'.__('Date').'</th><th class="no-break">'.__('Status').'</th></tr></thead><tbody>';
foreach ( $posts as $post ) {
$title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
switch ( $post->post_status ) {
case 'publish' :
case 'private' :
$stat = __('Published');
break;
case 'future' :
$stat = __('Scheduled');
break;
case 'pending' :
$stat = __('Pending Review');
break;
case 'draft' :
$stat = __('Draft');
break;
}
if ( '0000-00-00 00:00:00' == $post->post_date ) {
$time = '';
} else {
/* translators: date format in table columns, see http://php.net/date */
$time = mysql2date(__('Y/m/d'), $post->post_date);
}
$html .= '<tr class="found-posts"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
$html .= '<td><label for="found-'.$post->ID.'">' . esc_html( $title ) . '</label></td><td class="no-break">' . esc_html( $post_types[$post->post_type]->labels->singular_name ) . '</td><td class="no-break">'.esc_html( $time ) . '</td><td class="no-break">' . esc_html( $stat ). ' </td></tr>' . "\n\n";
}
$html .= '</tbody></table>';
$x = new WP_Ajax_Response();
$x->add( array(
'data' => $html
));
$x->send();
}
Javascript file open-posts.js
jQuery(document).ready(function($) {
// Find posts
var $findBox = $('#find-posts'),
$found = $('#find-posts-response'),
$findBoxSubmit = $('#find-posts-submit');
// Open
$('input.kc-find-post').live('dblclick', function() {
$findBox.data('kcTarget', $(this));
findPosts.open();
});
// Insert
$findBoxSubmit.click(function(e) {
e.preventDefault();
// Be nice!
if ( !$findBox.data('kcTarget') )
return;
var $selected = $found.find('input:checked');
if ( !$selected.length )
return false;
var $target = $findBox.data('kcTarget'),
current = $target.val(),
current = current === '' ? [] : current.split(','),
newID = $selected.val();
if ( $.inArray(newID, current) < 0 ) {
current.push(newID);
$target.val( current.join(',') );
}
});
// Double click on the radios
$('input[name="found_post_id"]', $findBox).live('dblclick', function() {
$findBoxSubmit.trigger('click');
});
// Close
$( '#find-posts-close' ).click(function() {
$findBox.removeData('kcTarget');
});
});

Resources