Add plus and minus buttons to WooCommerce - button

WooCommerce decided to remove the + and - buttons from the product and cart pages to increase or decrease quantity. They say it was redundant to have and if anyone wants them back just install another plugin from them.
I, like others, don't wish to install a plugin when using code is the wiser option. Better yet, we should've been given the choice to keep them or not. I digress...
I've scoured the net for a solution, tried a couple, but no joy. Would really appreciate assistance with code needed to bring them back and where that code should be placed.
Found an answer on another thread here, though not sure exactly where it goes or if this is what I need to bring the buttons back
// Input +- tweak
$(function(a){
a(".woocommerce-ordering").on("change", "select.orderby", function(){
a(this).closest("form").submit();
}),
a("div.quantity:not(.buttons_added), td.quantity:not(.buttons_added)").addClass("buttons_added").append('<input type="button" value="+" class="plus" />').prepend('<input type="button" value="-" class="minus" />'), a("input.qty:not(.product-quantity input.qty)").each(function(){
var b=parseFloat(a(this).attr("min"));b&&b>0&&parseFloat(a(this).val())<b&&a(this).val(b);
}),
a(document).on("click", ".plus, .minus", function(){
var b=a(this).closest(".quantity").find(".qty"),
c=parseFloat(b.val()),
d=parseFloat(b.attr("max")),
e=parseFloat(b.attr("min")),
f=b.attr("step");c&&""!==c&&"NaN"!==c||(c=0),
(""===d||"NaN"===d)&&(d=""),
(""===e||"NaN"===e)&&(e=0),
("any"===f||""===f||void 0===f||"NaN"===parseFloat(f))&&(f=1),
a(this).is(".plus")?b.val(d&&(d==c||c>d)?d:c+parseFloat(f)):e&&(e==c||e>c)?b.val(e):c>0&&b.val(c-parseFloat(f)),
b.trigger("change");
});
});
Thanks in advance!

Yes, I know the issue, really anoying, every theme that I create I need to fix this... Here is how I did it:
Create a folder in your theme folder: /woocommerce/global/
Create a file: quantity-input.php
Put the following content inside this file:
<?php
/**
* Product quantity inputs
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<div class="quantity">
<input type="text" pattern="[0-9]*" step="<?php echo esc_attr( $step ); ?>" <?php if ( is_numeric( $min_value ) ) : ?>min="<?php echo esc_attr( $min_value ); ?>"<?php endif; ?> <?php if ( is_numeric( $max_value ) ) : ?>max="<?php echo esc_attr( $max_value ); ?>"<?php endif; ?> name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" title="<?php _ex( 'Qty', 'Product quantity input tooltip', 'moto' ) ?>" class="input-text qty text" size="4" />
<span class="td-quantity-button plus">+</span>
<span class="td-quantity-button min">-</span>
</div>
And of course you would need some jQuery to make the buttons work:
$('.td-quantity-button').on('click', function () {
var $this = $(this);
var $input = $this.parent().find('input');
var $quantity = $input.val();
var $new_quantity = 0;
if ($this.hasClass('plus')) {
var $new_quantity = parseFloat($quantity) + 1;
} else {
if ($quantity > 0) {
var $new_quantity = parseFloat($quantity) - 1;
}
}
$input.val($new_quantity);
});
Please note that you will have to style these buttons and input field yourself.
Please also note you need jquery enqueud in your theme or plugin:
function theme_name_scripts() {
wp_enqueue_script( 'jquery' );
}
add_action( 'wp_enqueue_scripts', 'theme_name_scripts' );

If you want a clean solution to add "-" and "+" increment buttons to WooCommerce product and cart page, with easy customization options, I created a plugin which does it without overriding templates, through hooks only:
Qty Increment Buttons for WooCommerce
PHP and jQuery code is only part of solution, because multiple CSS manipulations are required to make these inserted buttons presentable. WooCommerce 3.0 comes with additional hooks for product page, so implementation is even easier, but they are not a must and I got it to work for older versions as well.
Here is my jQuery code:
// Make code work on page load (this js file is executed only on product and cart page).
$(document).ready(function(){
QtyChng();
});
// Make code work after executing AJAX on cart page. Support for default WooCommerce and plugins using AJAX on cart page.
$( document.body ).on( 'updated_cart_totals', function(){
QtyChng();
});
function QtyChng() {
$('.woocommerce form.cart, .woocommerce td.product-quantity').on( 'click', '.qib-button', function() {
// Find quantity input field corresponding to increment button clicked.
var qty = $( this ).siblings( '.quantity' ).find( '.qty' );
// Read value and attributes 'min', 'max', 'step'.
var val = parseFloat(qty.val());
var max = parseFloat(qty.attr( 'max' ));
var min = parseFloat(qty.attr( 'min' ));
var step = parseFloat(qty.attr( 'step' ));
// Change input field value if result is in min and max range.
if ( $( this ).is( '.plus' ) ) {
if ( val === max ) return false;
if ( val + step > max ) {
qty.val( max );
} else {
qty.val( val + step );
}
} else {
if ( val === min ) return false;
if ( val - step < min ) {
qty.val( min );
} else {
qty.val( val - step );
}
}
$( this ).siblings( '.quantity' ).find( '.qty' ).trigger("change");
});
}
})(jQuery);

<?php
/**
* Product quantity inputs
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<div class="quantity">
<input type="text" pattern="[0-9]*" step="<?php echo esc_attr( $step ); ?>" <?php if ( is_numeric( $min_value ) ) : ?>min="<?php echo esc_attr( $min_value ); ?>"<?php endif; ?> <?php if ( is_numeric( $max_value ) ) : ?>max="<?php echo esc_attr( $max_value ); ?>"<?php endif; ?> name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" title="<?php _ex( 'Qty', 'Product quantity input tooltip', 'moto' ) ?>" class="input-text qty text" size="4" />
<span class="td-quantity-button plus">+</span>
<span class="td-quantity-button min">-</span>
</div>

Related

Dokan Plugin Customization

I am using dokan plugin for multivendor website. I want to add some extra field in dokan vendor setting page. I use this
add_filter( 'dokan_settings_form_bottom', 'extra_fields', 10, 2);
function extra_fields( $current_user, $profile_info ){
$seller_url= isset( $profile_info['seller_url'] ) ?
$profile_info['seller_url'] : '';?>
<label class="dokan-w3 dokan-control-label" for="setting_address">
<?php _e( 'Website', 'dokan' ); ?>
</label>
<div class="dokan-w5">
<input type="text" class="dokan-form-control input-md valid" name="seller_url" id="reg_seller_url" value="<?php echo $seller_url; ?>" />
</div>
</div>
<?php }
//save the field value
add_action( 'dokan_store_profile_saved', 'save_extra_fields', 15 );
function save_extra_fields( $store_id ) {
if ( isset( $_POST['seller_url'] ) ) {
$dokan_settings = dokan_get_store_info($store_id);
$dokan_settings['seller_url'] = $_POST['seller_url'];
}
update_user_meta( $store_id, 'dokan_profile_settings', $dokan_settings
);
}
But when i use this i am unable to update the payment method.please help me
Thanks
You can try this way to save the filed value and it should solve your problem -
add_action( 'dokan_store_profile_saved', 'save_extra_fields', 15 );
function save_extra_fields( $store_id ) {
$dokan_settings = dokan_get_store_info($store_id);
if ( isset( $_POST['seller_url'] ) ) {
$dokan_settings['seller_url'] = $_POST['seller_url'];
}
update_user_meta( $store_id, 'dokan_profile_settings', $dokan_settings );
}
If the code works then I hope you will mark this topic as resolved!
I have tried this code - https://gist.github.com/nayemDevs/b629d4b1c27c794bdfb729ce6927069e#file-extra-field-php and it is working for me. However, I have checked with Dokan theme and Hestia pro theme. Did you check if there is any theme conflict or not?

How to change add-to-cart form?

Is there a way to change the WooCommerce add-to-cart form through functions.php?
The goal is to add a checkbox for an additional product. When the checkbox is checked this product will also be added to the cart after a click on the add to cart button.
I am looking for a solution which doesn't rely on javascript.
A better title would be "WooCommerce up-sells as checkboxes".
A lot of research and several strategies to tackle this problem lead me to a solution which I thought was not even possible in the beginning.
The solution is now exactly what I wanted. A non-JavaScript, no-template-override, but a simple and pure addition to functions.php. It works for simple and variable products (and probably with grouped and external products too).
It misses some nice features still. It won't work yet if an up-sell is a variable product. Quantity selection and limiting up-sells per item or order would be nice additions too. Based on the code below adding those features should not be a big deal anymore.
// create the checkbox form fields and add them before the cart button
add_action( 'woocommerce_before_add_to_cart_button', 'action_woocommerce_before_add_to_cart_form', 10, 0 );
function action_woocommerce_before_add_to_cart_form(){
global $woocommerce, $product;
// get the product up-sells
$upsells = $product->get_upsells();
// store the number of up-sells and pass it on to the add-to-cart hook
?>
<input type="hidden" name="upsells_size" value="<?php echo(sizeof($upsells)); ?>">
<div id="wb-upsell-div">
<?php
// iterate through all upsells and add an input field for each
$i = 1;
foreach( $upsells as $value ){
$product_id = $value;
?>
<input id="wb-upsell-checkboxes" type="checkbox" name="upsell_<?php echo($i) ?>" value="<?php echo($product_id); ?>"><?php echo( '' . get_the_title( $product_id ) . "". " ($" . get_post_meta( $product_id, '_regular_price', true) . ")"); ?><br>
<?php
$i++;
}
?>
</div>
<?php
}
// function to add all up-sells, where the checkbox have been checked, to the cart
add_action('woocommerce_add_to_cart', 'custom_add_to_cart', 10, 3);
function custom_add_to_cart() {
global $woocommerce;
// get the number of up-sells to iterate through
$upsell_size = $_POST['upsells_size'];
// iterate through up-sell fields
for ($i=1; $i<=$upsell_size; $i++){
// get the product id of the up-sell
$product_id = $_POST['upsell_' . $i];
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
And here is the CSS for formatting the <div>and the checkboxes. It goes into the style.css file:
#wb-upsell-div {
margin-top: 10px;
margin-bottom: 20px;
}
#wb-upsell-checkboxes{
}
So there's an actual answer to this question, you can add whatever you want inside the add to cart <form> using hooks. For example:
add_action( 'woocommerce_before_add_to_cart_button', 'so_34115452_add_input' );
function so_34115452_add_input(){
echo '<input type="checkbox" name="something"/>' . __( 'Some Checkbox', 'text-domain' );
}

How to show avatar only if it exists?

Is there any function in Wordpress that allows to hide the gravatar if id doesn't exists?
I have many authors that doesn't have a gravatar and all are displayed like this:
http://prntscr.com/98zsji
I would like to hide the default image.
I used the function validate_gravatar($email);, but it generated an error:
Fatal error: Call to undefined function validate_gravatar()
If I print $user_email it display correctly the user email.
You can use validate_gravatar which takes in the email address of the user and returns back true or false.
validate_gravatar($email); // returns true or false
How to use it in your code:
$user_email = get_the_author_meta('user_email');
if(validate_gravatar($user_email)) {
$author_avatar = get_avatar( get_the_author_meta( 'user_email', $author_id ), '78', '', get_the_author_meta( 'display_name', $author_id ) );
}
// Now just echo where ever you want the image, it will show a default image if no gravatar is present.
if(isset($author_avatar) && !empty($author_avatar)){
echo '<img src="'.$author_avatar.'" />';
}
// In your Functions.php
function validate_gravatar($email) {
$hash = md5(strtolower(trim($email)));
$uri = 'http://www.gravatar.com/avatar/' . $hash . '?d=404';
$headers = #get_headers($uri);
if (!preg_match("|200|", $headers[0])) {
$has_valid_avatar = FALSE;
} else {
$has_valid_avatar = TRUE;
}
return $has_valid_avatar;
}
Here is the filter that will do the trick:
function ns_filter_avatar($avatar, $id_or_email, $size, $default, $alt, $args)
{
$headers = #get_headers( $args['url'] );
if( ! preg_match("|200|", $headers[0] ) ) {
return;
}
return $avatar;
}
add_filter('get_avatar','ns_filter_avatar', 10, 6);
To work you have to add value 404 as third argument $default to get_avatar(). Example:
get_avatar( $user_email, 45, '404' )
I have been using the code below for a while and always work for me. The code is checked with PHPCS and WordPress Theme Standards and there is no errors or warnings.
The script profile-image.js is only enqueued on the respective page user-edit.php, that also applies for the media-upload and Thickbox scripts, this procedure will avoid any possible scripts conflict on your WordPress admin area.
/**
*
* Add custom user profile information
*
*/
add_action( 'show_user_profile', 'ns_show_extra_profile_fields' );
add_action( 'edit_user_profile', 'ns_show_extra_profile_fields' );
function ns_show_extra_profile_fields( $user ) { ?>
<h3>Extra profile information</h3>
<table class="form-table">
<tr>
<th><label for="image">Profile Image</label></th>
<td>
<img src="<?php echo esc_attr( get_the_author_meta( 'image', $user->ID ) ); ?>" style="height:50px;">
<input type="text" name="image" id="image" value="<?php echo esc_attr( get_the_author_meta( 'image', $user->ID ) ); ?>" class="regular-text" /><input type='button' class="button-primary" value="Upload Image" id="uploadimage"/><br />
<span class="description">Please upload your image for your profile.</span>
</td>
</tr>
</table>
<?php
}
/**
* Enqueue a script in the WordPress admin user-edit.php.
*
* #param int $pagenow Hook suffix for the current admin page.
*/
function ns_selectively_enqueue_admin_script( $hook ) {
global $pagenow;
if ($pagenow != 'user-edit.php') {
return;
}
wp_enqueue_script('media-upload');
wp_enqueue_script('thickbox');
wp_enqueue_style('thickbox');
wp_register_script( 'profile-image', get_template_directory_uri().'/js/profile-image.js', array('jquery-core'), false, true );
wp_enqueue_script( 'profile-image' );
}
add_action( 'admin_enqueue_scripts', 'ns_selectively_enqueue_admin_script' );
/*
* Save custom user profile data
*
*/
add_action( 'personal_options_update', 'ns_save_extra_profile_fields' );
add_action( 'edit_user_profile_update', 'ns_save_extra_profile_fields' );
function ns_save_extra_profile_fields( $user_id ) {
if ( !current_user_can( 'edit_user', $user_id ) )
return false;
if(isset($_POST['image'])) {
$imageprofile = sanitize_text_field( wp_unslash( $_POST['image'] ) );
update_user_meta( $user_id, 'image', $imageprofile );
}
}
profile-image.js:
jQuery(document).ready(function() {
jQuery(document).find("input[id^='uploadimage']").live('click', function(){
//var num = this.id.split('-')[1];
formfield = jQuery('#image').attr('name');
tb_show('', 'media-upload.php?type=image&TB_iframe=true');
window.send_to_editor = function(html) {
imgurl = jQuery('img',html).attr('src');
jQuery('#image').val(imgurl);
tb_remove();
}
return false;
});
});

How to set radio buttons in custom meta box checked?

I created a custom meta box where you can choose a value from some radio buttons and save it to the post_meta table in the wordpress database. With the following code I save the value:
function save_value_of_my_custom_metabox ($post_id, $post){
$post_id = get_the_ID();
$new_meta_value = ( isset( $_POST['the_name_of_the_radio_buttons'] ) ? sanitize_html_class( $_POST['the_name_of_the_radio_buttons'] ) : '' );
$meta_key = 'my_key';
update_post_meta( $post_id, $meta_key, $new_meta_value );
}
But if the post will be edited again I want the radio button with the current value to set checked. What is the best way to do that? Here is the function to display the meta box:
function my_custom_meta_box( $object, $box ) {
$post_id=get_the_ID();
$key='my_key';
$the_value_that_should_be_set_to_checked=get_post_meta( $post_id, $key);
//$the_value_that_should_be_set_to_checked[0] returns the value as string
?>
<label for="my_custom_metabox"><?php _e( "Choose value:", 'choose_value' ); ?></label>
<br />
<input type="radio" name="the_name_of_the_radio_buttons" value="value1">Value1<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value2">Value2<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value3">Value3<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value4">Value4<br>
<?php
}
I could write something like if(isset($the_value_that_should_be_set_to_checked[0])=="value of that line") echo "checked='checked'"; in every line but that doesn't seem very elegant to me. Using javascript is also pretty complicated in wordpress because I would have to use the hooks, enqueue the script and just for changing the checked property with one line of javascript it's not worth it. What's the best practice for that?
I am assuming that you are trying to add custom meta box for 'Posts'. Below code will work for you. It will show Radio buttons on add new post or edit post screen. Please read the comments in the code. It will help you in understanding the code.
You can use WordPress's checked function to decide whether to select the radio button or not.
Feel free to ask if you have any doubts.
/**
* Adds a box to the main column on the Post add/edit screens.
*/
function wdm_add_meta_box() {
add_meta_box(
'wdm_sectionid', 'Radio Buttons Meta Box', 'wdm_meta_box_callback', 'post'
); //you can change the 4th paramter i.e. post to custom post type name, if you want it for something else
}
add_action( 'add_meta_boxes', 'wdm_add_meta_box' );
/**
* Prints the box content.
*
* #param WP_Post $post The object for the current post/page.
*/
function wdm_meta_box_callback( $post ) {
// Add an nonce field so we can check for it later.
wp_nonce_field( 'wdm_meta_box', 'wdm_meta_box_nonce' );
/*
* Use get_post_meta() to retrieve an existing value
* from the database and use the value for the form.
*/
$value = get_post_meta( $post->ID, 'my_key', true ); //my_key is a meta_key. Change it to whatever you want
?>
<label for="wdm_new_field"><?php _e( "Choose value:", 'choose_value' ); ?></label>
<br />
<input type="radio" name="the_name_of_the_radio_buttons" value="value1" <?php checked( $value, 'value1' ); ?> >Value1<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value2" <?php checked( $value, 'value2' ); ?> >Value2<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value3" <?php checked( $value, 'value3' ); ?> >Value3<br>
<input type="radio" name="the_name_of_the_radio_buttons" value="value4" <?php checked( $value, 'value4' ); ?> >Value4<br>
<?php
}
/**
* When the post is saved, saves our custom data.
*
* #param int $post_id The ID of the post being saved.
*/
function wdm_save_meta_box_data( $post_id ) {
/*
* We need to verify this came from our screen and with proper authorization,
* because the save_post action can be triggered at other times.
*/
// Check if our nonce is set.
if ( !isset( $_POST['wdm_meta_box_nonce'] ) ) {
return;
}
// Verify that the nonce is valid.
if ( !wp_verify_nonce( $_POST['wdm_meta_box_nonce'], 'wdm_meta_box' ) ) {
return;
}
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Check the user's permissions.
if ( !current_user_can( 'edit_post', $post_id ) ) {
return;
}
// Sanitize user input.
$new_meta_value = ( isset( $_POST['the_name_of_the_radio_buttons'] ) ? sanitize_html_class( $_POST['the_name_of_the_radio_buttons'] ) : '' );
// Update the meta field in the database.
update_post_meta( $post_id, 'my_key', $new_meta_value );
}
add_action( 'save_post', 'wdm_save_meta_box_data' );
I found a working solution but I think this is not how you should do it. Still open for better solutions ;)
This code was added under the php code from above:
if(isset($$the_value_that_should_be_set_to_checked[0])){
$the_value_that_should_be_set_to_checked= $the_value_that_should_be_set_to_checked[0];
}
else{
$the_value_that_should_be_set_to_checked='';
}
Here's the code that I added below the radiobuttons:
<script type="text/javascript">
jQuery(document).ready(function () {
var checked_value= <?php echo json_encode($the_value_that_should_be_set_to_checked);?>;
if(checked_value!==''){
jQuery("input[name=the_name_of_the_radio_buttons][value="+checked_value+"]").attr('checked', 'checked');
}
});
</script>
P.S.: The $ selector will not work but that maybe depends on the theme you use.

Wordpress user profile display name - change from selectbox to textbox

Im trying to change the user profile "Display name publicly as" from a select box to a textbox. Any ideas on how this can be done? Couldnt find anything all all.
Two way to solve it. You edit the wordpress core file, which is not a good way. Or you can add an extra field on profile box using wordpress hook.
I am giving you the first way:
Go to wp-admin/user-edit.php
Open the file. Then find
<td>
<select name="display_name" id="display_name">
<?php
$public_display = array();
$public_display['display_nickname'] = $profileuser->nickname;
$public_display['display_username'] = $profileuser->user_login;
if ( !empty($profileuser->first_name) )
$public_display['display_firstname'] = $profileuser->first_name;
if ( !empty($profileuser->last_name) )
$public_display['display_lastname'] = $profileuser->last_name;
if ( !empty($profileuser->first_name) && !empty($profileuser->last_name) ) {
$public_display['display_firstlast'] = $profileuser->first_name . ' ' . $profileuser->last_name;
$public_display['display_lastfirst'] = $profileuser->last_name . ' ' . $profileuser->first_name;
}
if ( !in_array( $profileuser->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
$public_display = array( 'display_displayname' => $profileuser->display_name ) + $public_display;
$public_display = array_map( 'trim', $public_display );
$public_display = array_unique( $public_display );
foreach ( $public_display as $id => $item ) {
?>
<option id="<?php echo $id; ?>"<?php selected( $profileuser->display_name, $item ); ?>><?php echo $item; ?></option>
<?php
}
?>
</select>
</td>
Change it with
<th><label for="display_name"><?php _e('Display name publicly as'); ?> </label></th>
<td><input type="text" name="display_name" id="display_name" value="<?php echo esc_attr( $profileuser->display_name ); ?>" class="regular-text" /></td>
But still this is not a good solution.
I came across this same issue and used a bit of javascript to solve it. Wordpress allows you to set the display_name field to anything you want, so you can use the following script (in your theme's functions.php file) to convert the select to a text field.
function change_display_name_to_textfield() {
echo "><div>"; // don't remove '>'
?>
<script>
jQuery(function($) {
// replace display_name select with input
$('select#display_name').after( '<input type="text" name="display_name" id="display_name" value="' + $('#display_name').val() + '" class="regular-text">' ).remove();
})
</script>
<?php
echo "</div"; // don't add '>'
}
// hook into new user and edit user pages
add_action( "user_new_form_tag", "change_display_name_to_textfield" );
add_action( "user_edit_form_tag", "change_display_name_to_textfield" );
Note the weird use of opening/closing tags. This is because those particular hooks execute just before the end of the opening form tag. So you need to close the form tag, print your script, then print a final tag without closing it.
For admin user edit pages, I found one of the easiest way:
add_action( 'personal_options', 'rm_personal_options' );
function rm_personal_options($profileuser){
if( !is_admin() ) return; ?>
<script type="text/javascript">
jQuery(document).ready(function($){
//$("input#nickname").parent().parent().hide();
$("select#display_name").replaceWith(function(){
return '<input type="text" name="display_name" id="display_name" value="'+$(this).val()+'" class="regular-text" style="width:25em" />';
});
});
</script>
<?php
}
Simply paste it into the functions.php of the theme file :)

Resources