I'm building a WordPress theme and need to add custom controls in the customizer, the input field is showing up but when I change the value of input nothing happens.
Here is my code.
class WP_Customize_Custom_Control extends WP_Customize_Control {
public $type = 'custom_control';
function render_content(){
}
public function content_template() {
?>
<input type="text" id="custom_control" name="custom_control" />
<?php
}
}
function company_customize_register( $wp_customize ){
$wp_customize->register_control_type( 'WP_Customize_Custom_Control' );
$wp_customize->add_setting('custom_smthing', array( 'default' => get_theme_mod( "custom_smthing" ), 'transport' =>'postMessage' ) );
$wp_customize->add_control(new WP_Customize_Custom_Control($wp_customize,'custom_smthing',
array(
'label' => __( 'Custom Control', 'company' ),
'section' => 'body_backgrounds',
'settings' => 'custom_smthing',
)
)
);
}
add_action( 'customize_register', 'company_customize_register' );
and the js is
( function( $ ) {
console.log("test1");
wp.customize( 'custom_smthing', function( value ) {
console.log("test2");
value.bind( function( to ) {
console.log("test3");
} );
});
})( jQuery );
test1 and test2 are working but test3 never fires.
Maybe my answer is not what are you looking for, but content_template is for underscore JS templates. I'm not completely sure by your answer do you need it or not. But you can find additional information here.
If you remove register_control_type line and relocate your input into render_content method it will do a trick.
Your PHP part will be like
class WP_Customize_Custom_Control extends WP_Customize_Control {
public $type = 'custom_control';
public function render_content() {
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<input class="custom_control" id="custom_control" type="text" <?php $this->link(); ?> value="<?php echo esc_attr( $this->value() ); ?>">
</label>
<?php
}
}
function company_customize_register( $wp_customize ){
// $wp_customize->register_control_type( 'WP_Customize_Custom_Control' ); - remove this line
$wp_customize->add_setting('custom_smthing', array( 'default' => get_theme_mod( "custom_smthing" ), 'transport' =>'postMessage' ) );
$wp_customize->add_control(new WP_Customize_Custom_Control($wp_customize,'custom_smthing',
array(
'label' => __( 'Custom Control', 'company' ),
'section' => 'body_backgrounds',
'settings' => 'custom_smthing',
)
)
);
}
add_action( 'customize_register', 'company_customize_register' );
I Revised your code and found out that your code will not work in many scenarios or as per the latest WP version.
You did not mention the body_backgrounds section in your code. so I assume that Body Backgrounds is your custom section because I did not find the default body_backgrounds section in WordPress.
So I added a section.
$wp_customize->add_section( 'body_backgrounds' , array(
'title' => 'Body Backgrounds',
'priority' => 20,
) );
WP_Customize_Control is only loading when the theme customizer is actually used. So, you need to define your class within the function 'company_customize_register'. Otherwise, it will give PHP Fatal error: Class 'WP_Customize_Control' not found
You did not mention how you enqueue your js but better add dependency jquery and customize-preview.
function customizer_live_preview() {
wp_enqueue_script(
'theme-customizer',
get_template_directory_uri() . '/assets/js/theme-customizer.js',
array( 'jquery', 'customize-preview' ),
'1.0.0',
true
);
}
add_action( 'customize_preview_init', 'customizer_live_preview' );
You need to pass the data-customize-setting-link to your input to bind your value.
<input type="text" id="custom_smthing" name="custom_smthing" data-customize-setting-link="custom_smthing" />
PHP
function company_customize_register( $wp_customize ){
class WP_Customize_Custom_Control extends WP_Customize_Control {
public $type = 'custom_control';
function render_content(){ }
public function content_template() {?>
<input type="text" id="custom_smthing" name="custom_smthing" data-customize-setting-link="custom_smthing" />
<?php }
}
$wp_customize->register_control_type( 'WP_Customize_Custom_Control' );
$wp_customize->add_section( 'body_backgrounds' , array(
'title' => 'Body Backgrounds',
'priority' => 20,
) );
$wp_customize->add_setting('custom_smthing', array( 'default' => get_theme_mod( "custom_smthing" ) ? get_theme_mod( "custom_smthing" ) : '', 'transport' =>'postMessage' ) );
$wp_customize->add_control(new WP_Customize_Custom_Control($wp_customize,'custom_smthing',
array(
'label' => __( 'Custom Control', 'company' ),
'section' => 'body_backgrounds',
'settings' => 'custom_smthing',
)
)
);
}
add_action( 'customize_register', 'company_customize_register' );
function customizer_live_preview() {
wp_enqueue_script(
'theme-customizer',
get_template_directory_uri() . '/assets/js/theme-customizer.js',
array( 'jquery', 'customize-preview' ),
'1.0.0',
true
);
}
add_action( 'customize_preview_init', 'customizer_live_preview' );
"theme-customizer.js"
(function( $ ) {
"use strict";
wp.customize('custom_smthing', function(value) {
value.bind(function(value) {
console.log(value);
});
});
})( jQuery );
Tested and works.
test3 will only fire when the value of custom_smthing changes.
I have figured out the issue.
if the first two logs are fired then nothing is wrong in the question
there are no mistakes there and all is as instructed in the official wordpress themes development handbook.
the issue was in index.php
wp_head(); and wp_footer(); MUST exist
I removed them = only first two logs are fired
I put them on = all three logs are fired
what makes me angry is WHY this wasn't mentioned in the wordpress official handbook.
at the very end of the entire handbook yes
but it doesn't say it is essential for many things to work, including this one.
Related
I am currently trying to enqueue 2 Wordpress AJAX scripts in my functions.php file, but I seem to have hit an error. The first AJAX script works fine, but for the second I keep getting a 500 Internal Server Error.
What I have so far in my AJAX scripts is this:
This first block is for my first AJAX script located in my-ajax-script.js.
function lesson_watched_call(lesson_id_value) {
console.log('Lesson watched fn called.');
console.log(lesson_id_value);
$.post(my_ajax_obj.ajax_url, {
_ajax_nonce: my_ajax_obj.nonce, // nonce
action: "lesson_watched", // action call
lesson_value: lesson_id_value // data
});
}
This second block is for my second AJAX script located in fav-ajax-script.js.
function toggleFavTut(tutorial_id_value) {
console.log('Tutorial toggle fn called.');
console.log(tutorial_id_value);
$.post(my_ajax_obj.ajax_url, {
_ajax_nonce: my_ajax_obj.nonce, // nonce
action: "tutorial_fav_toggle", // action call
tutorial_value: tutorial_id_value // data
});
}
In my functions.php file, this is what I have:
/*---------------------------------------------------------------------------------*/
/* Enqeue AJAX Script and Define Lesson Watched Function */
/*---------------------------------------------------------------------------------*/
add_action( 'wp_enqueue_scripts', 'enqueue_ajax_scripts' );
function enqueue_ajax_scripts() {
wp_enqueue_script( 'ajax-script', get_template_directory_uri() . '/js/my-ajax-script.js', array('jquery') );
wp_localize_script( 'ajax-script', 'my_ajax_obj',
array( 'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'lesson_nonce_value' ),
)
);
wp_enqueue_script( 'ajax-script2', get_template_directory_uri() . '/js/fav-ajax-script.js', array('jquery') );
wp_localize_script( 'ajax-script2', 'my_ajax_obj',
array( 'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'tutorial_nonce_value' ),
)
);
}
function lesson_watched() {
$lastValue_php = wp_unslash( $_POST['lesson_value'] );
$current_user_id = get_current_user_id();
$found = get_user_meta( $current_user_id, 'lessons_watched_ids', true );
if ( !in_array( $lastValue_php, $found ) ) :
if( empty( $found ) ) :
update_user_meta( $current_user_id, 'lessons_watched_ids', array( $lastValue_php ) );
else :
$found[] = $lastValue_php;
update_user_meta( $current_user_id, 'lessons_watched_ids', $found );
endif;
endif;
wp_die(); // Ends all AJAX handlers
}
add_action('wp_ajax_nopriv_lesson_watched', 'lesson_watched');
add_action('wp_ajax_lesson_watched', 'lesson_watched');
/*---------------------------------------------------------------------------------*/
/* Enqeue AJAX Script and Define Tutorial Toggle Function */
/*---------------------------------------------------------------------------------*/
function tutorial_fav_toggle() {
$tutorial_value = wp_unslash( $_POST['tutorial_value'] );
$current_user_id = get_current_user_id();
$found = get_user_meta( $current_user_id, 'tutorial_favorited_ids', true );
if ( !in_array( $tutorial_value, $found ) ) :
$found[] = $tutorial_value;
update_user_meta( $current_user_id, 'tutorial_favorited_ids', $found );
else:
$key = array_search( $tutorial_value, $found );
unset( $found[$key] );
update_user_meta( $current_user_id, 'tutorial_favorited_ids', $found );
endif;
wp_die(); // Ends all AJAX handlers
}
add_action('wp_ajax_nopriv_tutorial_fav_toggle', 'tutorial_fav_toggle');
add_action('wp_ajax_tutorial_fav_toggle', 'tutorial_fav_toggle');
I first start out by enqueueing both scripts and then localizing each script. I'm wondering if maybe I have to use a different variable for some of the localize variables, but I am not certain about that. Would you have an tips on what to try to debug?
Per the docs, the second parameter to wp_localize_script should be unique.
$object_name is the name of the variable which will contain the data. Note that this should be unique to both the script and to the plugin or theme. Thus, the value here should be properly prefixed with the slug or another unique value, to prevent conflicts.
So, following your pattern the second function could use my_ajax_obj2 for the variable.
wp_enqueue_script( 'ajax-script', get_template_directory_uri() . '/js/my-ajax-script.js', array('jquery') );
wp_localize_script( 'ajax-script', 'my_ajax_obj',
array( 'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'lesson_nonce_value' ),
)
);
wp_enqueue_script( 'ajax-script2', get_template_directory_uri() . '/js/fav-ajax-script.js', array('jquery') );
wp_localize_script( 'ajax-script2', 'my_ajax_obj2',
array( 'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'tutorial_nonce_value' ),
)
);
Do take care to make your variable specific to your application, too. These variables all effectively are just properties on the global window object and everything can read/write them, so make sure they are unique.
I'm working on a WordPress theme and I've added a select box to allow users to select a font for their site. I figured I'd use the Google Fonts API to grab the list of fonts rather than add all 900-and-something manually, but when I call the API I'm unable to append the returned data as options in the select box.
This is the PHP code for my select box class:
class Customize_Select_Control extends WP_Customize_Control {
public $type = 'select';
public function render_content() {
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<select <?php $this->link(); ?> id="<?php echo str_replace(' ','-',strtolower(esc_html( $this->label ))); ?>-select">
<option value="<?php echo $this->value(); ?>" selected><?php echo $this->value(); ?></option>
</select>
</label>
<?php
}
}
I've then added a section, setting and control to the customiser using the following code:
// Add Font Section
$wp_customize->add_section( 'fonts' , array(
'title' => __( 'Font', 'wordpress' ),
'priority' => 100,
'description' => __( 'Pick a font for your website.', 'wordpress' )
) );
// Add the setting & control for the font
$wp_customize->add_setting( 'font-select' , array(
'default' => 'Open Sans',
'transport' => 'postMessage',
) );
$wp_customize->add_control( new Customize_Select_Control( $wp_customize, 'font-select', array(
'label' => __( 'Font', 'wordpress' ),
'section' => 'fonts',
'settings' => 'font-select',
) ) );
The following code is supposed to append the options to the select box:
$.ajax({
type: "GET",
url: "https://www.googleapis.com/webfonts/v1/webfonts?key=[REDACTED]&sort=popularity&fields=items",
dataType: "json",
success: function (result, status, xhr){
console.log(result.items);
for (var i = 0; i<result.items.length; i++){
var family = result.items[i].family;
console.log(family);
$('#font-select').append(`<option value="${family}">${family}</option>`);
}
},
error: function (xhr, status, error) {
alert("There was an error loading the Google fonts API: " + status + " " + error + " " + xhr.status + " " + xhr.statusText + "\n\nPlease save your changes and refresh the page to try again.")
}
});
If I change #font-select to body, it appends the options just fine, but however I try and append them to the select box, it just doesn't work. Any idea why and how I can make this work?
You can add Option value in select box in customizer admin panel as by below code :
Full code of your requirements
you just have to add your google font api key in scripts
where I have used 'twentynineteen' theme slug name you can use your theme slug name
There are 3 parts:
1) function mytheme_customize_register( $wp_customize ) {
//All our sections, settings, and controls will be added here
$wp_customize->add_section( 'fonts' , array(
'title' => __( 'Font', 'twentynineteen' ),
'priority' => 100,
'description' => __( 'Pick a font for your website.', 'twentynineteen' )
) );
// Add the setting & control for the font
$wp_customize->add_setting( 'font-select' , array(
'type' => 'select',
'default' => 'Roboto',
'transport' => 'postMessage',
) );
$wp_customize->add_control( 'font-select', array(
'type' => 'select',
'priority' => 10, // Within the section.
'section' => 'core', // Required, core or custom.
'description' => __( 'This is a date control with a red border.' ),
'choices' => array( // Optional.
'wordpress' => __( 'Roboto' ),
'hamsters' => __( 'Lato' ),
'jet-fuel' => __( 'Muli' ),
),
'label' => __( 'Font', 'twentynineteen' ),
'section' => 'fonts',
'settings' => 'font-select',
) );
}
add_action( 'customize_register', 'mytheme_customize_register' );
now add scripts file
2) function add_font_scripts(){
wp_enqueue_script('custom_js_script', get_bloginfo('template_url').'/js/custom-scripts.js', array('jquery'));
}
add_action( 'admin_enqueue_scripts', 'add_font_scripts' );
now last step please add below script in this file custom-scripts.js which we just enqueue above
3) var $= jQuery;
$(document).ready(function(){
$.ajax({
type: "GET",
url: "https://www.googleapis.com/webfonts/v1/webfonts?key=apikey&sort=popularity&fields=items",
dataType: "json",
success: function (result, status, xhr){
var outputstate = [];
console.log(result.items);
for (var i = 0; i<result.items.length; i++){
var family = result.items[i].family;
console.log(family);
outputstate.push('<option value="'+ family +'">'+ family +'</option>');
$('#_customize-input-font-select').html(outputstate.join(''));
}
},
error: function (xhr, status, error) {
alert("There was an error loading the Google fonts API: " + status + " " + error + " " + xhr.status + " " + xhr.statusText + "\n\nPlease save your changes and refresh the page to try again.")
}
});
});
I have try this code and It's Working fine!
I Hope this one is help you!
Your AJAX Success Callback is looking for the dropdown with id as font-select. However, the id of the Dropdown is based on the Label (which happens to be font).
The ID of the dropdown is created by following line of code in render_content method.
<?php echo str_replace(' ','-',strtolower(esc_html( $this->label ))); ?>
$this->label here will refer to the Fonts. Since you are using strtolower it will be fonts. I suggest you pass another variable for the id and populate it using that variable.
I am making a WordPress Plugin that adds an option to add a custom gift voucher to the checkout page. I have managed to get the gift voucher inputs and "apply now" button working and it adds the voucher value to the checkout totals, and it adjusts the total accordingly.
The problem is that my plugin seems to cause the "Place order" button to not be clickable. When I deactivate the plugin the checkout button works fine, so there is something in the plugin code that is causing the conflict. I've checked in the browser console and there are no errors being displayed for this page. Here is the code so far:
function my_init() {
if (!is_admin()) {
// comment out the next two lines to load the local copy of jQuery
wp_deregister_script('jquery');
wp_register_script('jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js', false, '1.3.2');
wp_enqueue_script('jquery');
}
}
function giftvoucher_front_end_scripts() {
wp_enqueue_script( 'my_custom_script', plugin_dir_url( __FILE__ ) . 'js/gift_voucher.js' , array( 'jquery' ), '', true );
}
add_action( 'wp_enqueue_scripts', 'giftvoucher_front_end_scripts' );
// Displaying a select field and a submit button in checkout page
function gift_voucher_value_check() {
echo '<a class="button alt" name="gift_voucher_action_btn" id="gift_voucher_action" value="Apply" data-value="gift_voucher_data_value">Apply Now</a>';
}
add_action( 'woocommerce_checkout_after_customer_details', 'gift_voucher_value_check', 10, 0 );
// jQuery - Ajax script
function gift_voucher_redeem_script() {
// Only checkout page
if ( ! is_checkout() ) return;
?>
<script type="text/javascript">
jQuery( function($){
$('#gift_voucher_action').on('click', function() {
redeemvoucher();
$.ajax({
type: "post",
url: wc_checkout_params.ajax_url,
data: {
'action' : 'gift_voucher_redeem',
//'gift_voucher_value' : $("#rx-redemption-points").val()
'gift_voucher_value' : $("#gift_voucher_redeem").val()
},
success: function(response) {
$('body').trigger('update_checkout');
console.log('response: '+response); // just for testing | TO BE REMOVED
},
error: function(error){
console.log('error: '+error); // just for testing | TO BE REMOVED
}
});
})
}
</script>
<?php
}
add_action( 'wp_footer', 'gift_voucher_redeem_script' );
// Wordpress Ajax code (set ajax data in Woocommerce session)
add_action( 'wp_ajax_gift_voucher_redeem', 'gift_voucher_redeem' );
add_action( 'wp_ajax_nopriv_gift_voucher_redeem', 'gift_voucher_redeem' );
function gift_voucher_redeem() {
if( isset($_POST['gift_voucher_value']) ){
WC()->session->set( 'custom_fee', esc_attr( $_POST['gift_voucher_value'] ) );
echo true;
}
exit();
}
add_action( 'wp_ajax_gift_voucher_redeem', 'gift_voucher_redeem' );
add_action( 'wp_ajax_nopriv_gift_voucher_redeem', 'gift_voucher_redeem' );
// Add a custom dynamic discount based on gift_voucher_data_value
function gift_voucher_value_discount( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for targeted shipping method
if ( WC()->session->__isset( 'custom_fee' ) )
$discount = (float) WC()->session->get( 'custom_fee' );
if( isset($discount) && $discount > 0 )
$cart->add_fee( __( 'Giftvoucher discount', 'woocommerce' ), -$discount );
}
add_action( 'woocommerce_cart_calculate_fees', 'gift_voucher_value_discount', 20, 1 );
// Add the gift voucher fields to the checkout page
function customise_checkout_field($checkout)
{
echo '<div id="customise_checkout_field"><h3>' . __('Have a Giftvoucher?') . '</h3>';
echo '<form>';
woocommerce_form_field('voucher_number_field', array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
) ,
'label' => __('Enter your giftvoucher number') ,
'id' => 'gift_voucher_number',
'placeholder' => __('19 digits, no spaces') ,
'required' => true,
) , $checkout->get_value('voucher_number_field'));
woocommerce_form_field('pin_field', array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
) ,
'id' => 'gift_voucher_pin',
'label' => __('Enter your PIN') ,
'placeholder' => __('4 digits') ,
'required' => true,
) , $checkout->get_value('pin_field'));
woocommerce_form_field('redeem_amount_field', array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
) ,
'label' => __('Amount to redeem $') ,
'id' => 'gift_voucher_redeem',
'placeholder' => __('0.00') ,
'required' => true,
) , $checkout->get_value('redeem_amount_field'));
//echo '<input type="button" value="Redeem Giftvoucher" onclick="redeemvoucher()"';
echo '<span id="redeemed"></span>';
echo '</form>';
echo '</div>';
}
add_action('woocommerce_after_order_notes', 'customise_checkout_field');
Can anyone assist me in finding what is causing this conflict with the "Place order" button? Thanks in advance.
Well it turns out that the answer was that the "Apply now" button was actually outside of the form tags... which is okay, I can live with that... but when I commented out the form tags, the checkout works perfectly when clicking the "Place order" button.
Must give credit to a colleague who had a look at the code and pointed out the issue to me... Thanks James!
I am trying to add a fee to checkout based on whether or not a custom checkbox I've added it checked. I am really close to getting this to work, but I'm having issues getting the post values to determine if the fee should be applied or not.
Here is the code I have for my custom field:
add_action( 'woocommerce_after_checkout_billing_form', 'my_custom_fields' );
function my_custom_fields( $checkout ) {
echo '<div id="message_fields"><h3>' . __('Add a Message') . '</h3>';
woocommerce_form_field( 'add_gift_message', array(
'type' => 'checkbox',
'class' => array('gift_message form-row-wide'),
'label' => __('5x7 Enclosed Personal Message - $4'),
'placeholder' => __(''),
), $checkout->get_value( 'add_gift_message' ));
woocommerce_form_field( 'gift_message', array(
'type' => 'textarea',
'class' => array('gift_message_text form-row-wide'),
'label' => false,
'placeholder' => __('Your message'),
), $checkout->get_value( 'gift_message' ));
echo '</div>';
}
This works, and the fields show up perfectly.
At the bottom of form-checkout.php in my theme, I have added this javascript to update the cart total when the field it checked:
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#add_gift_message').click(function(){
if ( $(this).is(':checked') ) {
$('#gift_message_field').show();
var gift_message= true;
} else {
$('#gift_message_field').hide();
var gift_message = false;
}
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: $( 'form.checkout' ).serialize(),
success: function( response ) {
if ( response ) {
var order_output = $(response);
$( '#order_review' ).html( $.trim( order_output ) );
$('body').trigger('update_checkout');
}
},
error: function(code){
},
dataType: 'html'
});
});
});
</script>
This updates the order total and runs the following code (this is where the problem is):
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_fee( $data ){
global $woocommerce;
if ( isset($_POST['add_gift_message']) )
$woocommerce->cart->add_fee( 'Personal Gift Message', '4.00', true, 'standard' );
}
I know this part is being called because if I take out if ( isset($_POST['add_gift_message']) ), it adds the fee. What I'm having trouble with is determining if the field has been checked or not - I can't seem to get the POST values inside of woo_add_cart_fee no matter what I do.
Does anyone know how to get this to work? Thank you!!
The reason why you unable to get value from $_POST['add_gift_message'] is because update_checkout is an ajax event and it serialise form data into $_POST['post_data']. So, in order to cater for getting the value before (ajax) and during(non-ajax) user check out, you can get that by using below code:
if ( isset( $_POST['post_data'] ) ) {
parse_str( $_POST['post_data'], $post_data );
} else {
$post_data = $_POST; // fallback for final checkout (non-ajax)
}
if ( isset( $post_data['add_gift_message'] ) ) {
$woocommerce->cart->add_fee( 'Personal Gift Message', '4.00', true, 'standard' );
}
for reference, can see this post
I have an item with the following data :
var item = {
id : "124",
name : "xxx",
price : "13.13",
quantity : 1,
options : {
"size" : "xl",
"color": "pink"
}
};
When the user clicks on "Add to Cart" I'd like to make an Ajax Request using the WC API and add the above item to the Cart.
jQuery.ajax({
url: "some/woocommerce/api/add/to/cart/request/path",
data: item,
type: "POST"
});
Then on the Cart Page I'd like to make another Ajax Request using the WC API and retrieve the contents of the cart.
I haven't found any documentation (official or unofficial) on how to do that from the client using Javascript.
Does anyone know and can provide me with an example please?
Also, does anyone know why the WooCommerce Api Documentation is so horrible (lacking any kind of information regarding obvious/standard questions like the above). I'm seriously thinking of having our company switch to Shopify.
You can investigate how WooCommerce is adding items to the cart via ajax directly in the code.... the callback is located in includes/class-wc-ajax.php. WooCommerce already does this on product "loops" (product archives), so I don't think you need to reinvent the wheel and if their existing code doesn't work for what you are trying to do, then you should be able to borrow heavily from it.
The beginning of that file has a loop with all the WooCommerce Ajax actions, but we can track down that the add to cart is basically this:
add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart', array( 'WC_AJAX', 'add_to_cart' ) );
And it's callback is a little further down the file:
/**
* AJAX add to cart
*/
public static function add_to_cart() {
ob_start();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) ) {
do_action( 'woocommerce_ajax_added_to_cart', $product_id );
if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
wc_add_to_cart_message( $product_id );
}
// Return fragments
self::get_refreshed_fragments();
} else {
// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
'error' => true,
'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
);
wp_send_json( $data );
}
die();
}
If you want to view their add to cart ajax call, the JS for that is located in assest/js/frontend/add-to-cart.js.
EDIT
Now that I know you are looking to add a variation, maybe we can tweak the above.
First, I think you'll need to pass the AJAX url to your script:
wp_enqueue_script( 'wc-variation-add-to-cart', 'source-to-script/your-script.js' );
$vars = array( 'ajax_url' => admin_url( 'admin-ajax.php' ) );
wp_localize_script( 'wc-variation-add-to-cart', 'WC_VARIATION_ADD_TO_CART', $vars );
Then your AJAX call would look something like this:
jQuery.ajax({
url: WC_VARIATION_ADD_TO_CART.ajax_url,
data: {
"action" : "woocommerce_add_variation_to_cart",
"product_id" : "124",
"variation_id" : "125",
"quantity" : 1,
"variation" : {
"size" : "xl",
"color": "pink"
},
},
type: "POST"
});
Basically to add a specific variation you need the variation's ID in addition to all its specific options.
And finally the new callback for the woocommerce_add_variation_to_cart ajax action would be along the lines of the following:
add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'so_27270880_add_variation_to_cart' );
function so_27270880_add_variation_to_cart() {
ob_start();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
$variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : '';
$variations = ! empty( $_POST['variation'] ) ? (array) $_POST['variation'] : '';
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
do_action( 'woocommerce_ajax_added_to_cart', $product_id );
if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
wc_add_to_cart_message( $product_id );
}
// Return fragments
WC_AJAX::get_refreshed_fragments();
} else {
// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
'error' => true,
'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
);
wp_send_json( $data );
}
die();
}
Mostly, I'm just copying WooCommerce's approach and adding in the 2 variables needed for adding variations. Totally untested, but I hope it helps.
If anyone is interested I've also written a "remove from cart" function to counter the add to cart. My project called for radio buttons on checkout so I needed to add a product and remove the alternative it was already there:
Here's the php:
function remove_from_cart( $product_id ) {
$cart_contents = WC()->cart->get_cart();
if (empty($product_id)) { $product_id = $_POST['product_id']; }
foreach ($cart_contents as $product_key => $product){
if ($product['variation_id'] == $product_id){
WC()->cart->remove_cart_item($product_key);
}
}
}
add_action( 'wp_ajax_nopriv_remove_from_cart', 'remove_from_cart' );
And then here's the jQuery:
function remove_item_from_cart(product){
var data = {
"action" : "remove_from_cart",
"product_id" : product,
};
jQuery.post(WC_VARIATION_ADD_TO_CART.ajax_url, data, function(response) {
$(document.body).trigger("update_checkout");
});
}
The if(empty)... in the php was so I could call the function from the server side as well if I needed to.