Add and manage Product custom upload field in Woocommerce 3 - php
I am trying to add a file upload along with radio inputs in a custom woocommerce page; where all the products are showing in a list view.
The Custom Page CODE:
<?php /*
Template Name: Custom Woo Product List Page
*/ ?>
<?php get_header();?>
<div class="inn_page">
<table id="wh_table" class="table table-hover" width="100%" cellspacing="0">
<thead>
<tr>
<th></th>
<th>PRODUCT</th>
<th>Monogram letter or Message Box</th>
<th>PRICE</th>
<th>Product Total Quantity</th>
<th></th>
</tr>
</thead>
<tbody>
<?php
$args = array(
'post_type' => array('product', 'product_variation'),
'post_status' => array('publish'),
'posts_per_page' => -1,
'product_cat' => '',
'post__in' => array( 178, 39, 180, 101, 182, 108, 184, 171, 872, 877, 206, 197, 1028, 330, 216, 451, 481, 478, 589 ),
'orderby' => 'post__in',
//'order' => 'DESC',
'paged' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1 );
$wp_query = new WP_Query( $args );
while ( $wp_query->have_posts() ) : $wp_query->the_post();
global $product;
?>
<?php if ( $product->is_type( 'variable' ) )
{
show_variable_products_list();
}
else
{
?>
<tr class="product-<?php echo esc_attr( $product->id ); ?> variations_form" data-role="product">
<form action="<?php echo esc_url( $product->add_to_cart_url() ); ?>" class="cart" name="upload_form" id="upload_form" method="post" enctype='multipart/form-data'>
<a href="<?php echo get_permalink( $wp_query->post->ID ) ?>" title="<?php echo esc_attr($wp_query->post->post_title ? $wp_query->post->post_title : $wp_query->post->ID); ?>">
<td class="image">
<?php woocommerce_show_product_sale_flash( $post, $product ); ?>
<?php if (has_post_thumbnail( $wp_query->post->ID )) echo get_the_post_thumbnail($wp_query->post->ID, 'wh_catalog'); else echo '<img src="'.woocommerce_placeholder_img_src().'" alt="Placeholder" width="150px" height="150px" />'; ?>
</td>
<td class="title">
<h3><?php the_title(); ?></h3>
<?php if ( ($product->get_id() == 178) || ($product->get_id() == 589) ) { ?>
<b>Sterling Silver</b>
<?php } ?>
</td>
<td class="note">
<?php letter_note(); ?>
<?php msg_note(); ?>
<?php upload_logo(); ?>
</td>
<td class="wh-price">
<span class="hiddenPrice"><?php echo $product->get_price_html() ?></span>
<span class="woocommerce-Price-amount ajaxPrice"><?php echo $product->get_price_html() ?></span>
</td>
</a>
<td class="quantity-field">
<?php woocommerce_quantity_input(); ?>
</td>
<td class="button-row">
<input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $product->id ); ?>" />
<input type="hidden" name="product_id" value="<?php echo esc_attr( $product->id ); ?>" />
<div class="wh-button">
<button type="submit" class="single_add_to_cart_button btn btn-primary button wh-btn"><span class="glyphicon glyphicon-tag"></span> ADD TO CART</button>
</div>
</td>
</form>
</tr>
<?php } ?>
<?php endwhile; ?>
</tbody>
</table><!--/.products-->
<?php wp_reset_query(); ?>
</div>
<?php get_footer();?>
For variations to show in list view as different items/products in funtions.php
<?php
//----------------------------- START PRODUCT LIST VIEW PAGE CODE ----------------------------------
//-------------------------------------- Variations in Table List ---------------------------
function show_variable_products_list(){
global $product, $post;
$variations = find_valid_variations();
asort($variations);
foreach ($variations as $key => $value) {
if( !$value['variation_is_visible'] ) continue; ?>
<?php
$id_variation = $value['variation_id']
?>
<tr class="product-<?php echo esc_attr( $product->id ); ?> variation-<?php echo $value['variation_id']?> variations_form" data-role="product">
<form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo absint( $product->id ); ?>" data-product_variations="<?php echo htmlspecialchars( json_encode( $available_variations ) ) ?>">
<td class="image">
<?php echo '<img src="'.$value['image_src'].'" alt="'.$product->get_title().'-'.$value['variation_id'].'" width="150px" height="150px" />'; ?>
</td>
<td class="title">
<h3><?php the_title(); ?></h3><br />
<b class="var-name"><?php
foreach($value['attributes'] as $attr_name => $attr_value ) {
$attr_name = 'pa_setting';
$attr = get_term_by('slug', $attr_value, $attr_name);
$attr_value = $attr->name;
echo $attr_value, ' ';
}
?></b>
<?php echo $id_variation ?>
</td>
<td class="note">
<?php letter_note(); ?>
<?php msg_note(); ?>
<?php upload_logo(); ?>
</td>
<td class="wh-price">
<span class="hiddenPrice"><?php echo $value['price_html'];?></span>
<span class="woocommerce-Price-amount ajaxPrice"><?php echo $value['price_html'];?></span>
</td>
<?php if( $value['is_in_stock'] ) { ?>
<td class="quantity-field">
<?php woocommerce_quantity_input(); ?>
</td>
<td class="button-row">
<?php
if(!empty($value['attributes'])){
foreach ($value['attributes'] as $attr_key => $attr_value) {
?>
<input type="hidden" name="<?php echo $attr_key?>" value="<?php echo $attr_value?>">
<?php
}
}
?>
<div class="wh-button">
<button type="submit" class="single_add_to_cart_button btn btn-primary button wh-btn"><span class="glyphicon glyphicon-tag"></span> ADD TO CART</button>
</div>
<input type="hidden" name="variation_id" class="variation_id" value="<?php echo $value['variation_id']?>" />
<input type="hidden" name="product_id" value="<?php echo esc_attr( $post->ID ); ?>" />
<input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $post->ID ); ?>" />
<?php } else { ?>
<p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
<?php } ?>
</td>
</form>
</tr>
<?php
}
}
?>
<?php
function find_valid_variations() {
global $product;
if ( $product->get_id() == 330 ) {
$variations = $product->get_available_variations();
//$attributes = $product->get_attributes();
$new_variants = array();
/* Show only the variations listed below */
foreach( $variations as $variation ) {
if ( $variation["variation_id"] == 971 || $variation["variation_id"] == 958 || $variation["variation_id"] == 945 || $variation["variation_id"] == 422 || $variation["variation_id"] == 412 || $variation["variation_id"] == 386 || $variation["variation_id"] == 358 ) {
$valid = true;
if( $valid )
$new_variants[] = $variation;
}
}
}
elseif ( $product->get_id() == 216 ) {
$variations = $product->get_available_variations();
$new_variants = array();
foreach( $variations as $variation ) {
if ( $variation["variation_id"] == 1010 || $variation["variation_id"] == 997 || $variation["variation_id"] == 984 || $variation["variation_id"] == 321 || $variation["variation_id"] == 295 || $variation["variation_id"] == 267 || $variation["variation_id"] == 237 ) {
$valid = true;
if( $valid )
$new_variants[] = $variation;
}
}
}
else {
$variations = $product->get_available_variations();
$attributes = $product->get_attributes();
$new_variants = array();
foreach( $variations as $variation ) {
$valid = true;
foreach( $attributes as $slug => $args ) {
if( array_key_exists("attribute_$slug", $variation['attributes']) && !empty($variation['attributes']["attribute_$slug"]) ) {
// Exists
} else {
$valid = false;
foreach( explode( '|', $attributes[$slug]['value']) as $attribute ) {
$attribute = trim( $attribute );
$new_variant = $variation;
$new_variant['attributes']["attribute_$slug"] = $attribute;
$new_variants[] = $new_variant;
}
}
}
if( $valid )
$new_variants[] = $variation;
}
}
return $new_variants;
}
add_filter( 'woocommerce_variable_add_to_cart', 'show_variable_products_list', 10, 2 );
?>
I am able to add the radio values to cart & order but not able to do anything with file upload.
Please take a look:
add_action("woocommerce_before_add_to_cart_button", "upload_logo", 9);
function upload_logo(){
?>
<div>
<p>Want to add Logo? <input type="checkbox" id="showHide" onclick="myFunction()"><b>Tick</b></p>
<p id="hiddenInputs" style="display:none">
<label for="radio_field">
Where you want the logo?
<input type="radio" name="radio_field" checked="checked" value="Front Side"> Front Side
<input type="radio" name="radio_field" value="Back Side"> Back Side
<input type="radio" name="radio_field" value="Both Side"> Both Side
</label> <br />
<label for="file_field">
Upload logo: <input type="file" name="file_field" value="">
</label> <br />
</p>
</div>
<script>
function myFunction() {
var checkboxToShowInputs = document.getElementById("showHide");
var showInputs = document.getElementById("hiddenInputs");
if (checkboxToShowInputs.checked == true){
showInputs.style.display = "block";
} else {
showInputs.style.display = "none";
}
}
</script>
<?php
}
/* Add File custom data to the cart item */
function file_upload_add_cart_item_data( $cart_item, $product_id ){
if( isset( $_POST['file_field'] ) ) {
$cart_item['logo_upload'] = $_POST['file_field'];
}
return $cart_item;
}
add_filter( 'woocommerce_add_cart_item_data', 'file_upload_add_cart_item_data', 10, 2 );
/* Add Radio custom data to the cart item */
// Stores the custom field value in Cart object
add_action( 'woocommerce_add_cart_item_data', 'save_custom_product_field_data', 10, 2 );
function save_custom_product_field_data( $cart_item, $product_id ) {
if( isset( $_REQUEST['radio_field'] ) ) {
$cart_item[ 'side_radio' ] = $_REQUEST['radio_field'];
// below statement make sure every add to cart action as unique line item
$cart_item['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'my_order_data', $_REQUEST['radio_field'] );
}
return $cart_item;
}
/* Load File cart data from session */
function file_upload_get_cart_item_from_session( $cart_item, $values ) {
if ( isset( $values['logo_upload'] ) ){
$cart_item['logo_upload'] = $values['logo_upload'];
}
return $cart_item;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'file_upload_get_cart_item_from_session', 20, 2 );
/* Load Radio cart data from session */
function radio_get_cart_item_from_session( $cart_item, $values ) {
if ( isset( $values['side_radio'] ) ){
$cart_item['side_radio'] = $values['side_radio'];
}
return $cart_item;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'radio_get_cart_item_from_session', 20, 2 );
/* Add File meta to order item */
function file_upload_add_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['logo_upload'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'logo_upload', $values['logo_upload'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'file_upload_add_order_item_meta', 10, 2 );
/* Add Radio meta to order item */
function radio_add_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['side_radio'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'side_radio', $values['side_radio'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'radio_add_order_item_meta', 10, 2 );
/* Get File item data to display in cart */
function file_upload_get_item_data( $other_data, $cart_item ) {
if ( ! empty ( $cart_item['logo_upload'] ) ){
$other_data[] = array(
'name' => __( 'Logo ', 'woocommerce' ),
'value' => $cart_item['logo_upload']
);
}
return $other_data;
}
add_filter( 'woocommerce_get_item_data', 'file_upload_get_item_data', 10, 2 );
/* Get Radio item data to display in cart */
function radio_get_item_data( $other_data, $cart_item ) {
if ( ! empty ( $cart_item['side_radio'] ) ){
$other_data[] = array(
'name' => __( 'Side ', 'woocommerce' ),
'value' => $cart_item['side_radio']
);
}
return $other_data;
}
add_filter( 'woocommerce_get_item_data', 'radio_get_item_data', 10, 2 );
/* Show File field in order overview */
function file_upload_order_item_product( $cart_item, $order_item ){
if( isset( $order_item['logo_upload'] ) ){
$cart_item_meta['logo_upload'] = $order_item['logo_upload'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_item_product', 'file_upload_order_item_product', 10, 2 );
/* Show Radio field in order overview */
function radio_order_item_product( $cart_item, $order_item ){
if( isset( $order_item['side_radio'] ) ){
$cart_item_meta['side_radio'] = $order_item['side_radio'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_item_product', 'radio_order_item_product', 10, 2 );
/* Add the File Upload field to order emails */
function file_upload_email_order_meta_fields( $fields ) {
$fields['custom_field'] = __( 'Logo ', 'woocommerce' );
return $fields;
}
add_filter('woocommerce_email_order_meta_fields', 'file_upload_email_order_meta_fields');
/* Add the Radio field to order emails */
function radio_email_order_meta_fields( $fields ) {
$fields['custom_field'] = __( 'Side ', 'woocommerce' );
return $fields;
}
add_filter('woocommerce_email_order_meta_fields', 'radio_email_order_meta_fields');
Here's the AJAX PHP
function ajax_add_to_cart_script() {
wp_enqueue_script( 'add-to-cart-wh_ajax', plugins_url() . '/wh-page-ajax-add-to-cart/js/add-to-cart-wh.js', array('jquery'), '', true );
}
add_action( 'wp_enqueue_scripts', 'ajax_add_to_cart_script',99 );
add_action( 'wp_ajax_woocommerce_add_to_cart_wh_sh', 'woocommerce_add_to_cart_wh_sh_callback' );
add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart_wh_sh', 'woocommerce_add_to_cart_wh_sh_callback' );
function woocommerce_add_to_cart_wh_sh_callback() {
ob_start();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$quantity = empty( $_POST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_POST['quantity'] );
$variation_id = $_POST['variation_id'];
$variation = $_POST['variation'];
$letter = $_POST['_letter'];
$message = $_POST['_message'];
$radio = $_POST['radio_field'];
//$file = $_POST['file_field'];
$file = $_FILES['id_proof'];;
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $quantity, $cart_item_data, $letter, $message, $radio, $file );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $letter, $message, $radio, $file ) ) {
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 {
$this->json_headers();
// 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 )
);
echo json_encode( $data );
}
die();
}
And here's the edited js
/* AJAX Add to Cart Button */
jQuery(function($) {
// wc_add_to_cart_params is required to continue, ensure the object exists
if (typeof wc_add_to_cart_params === 'undefined')
return false;
// Ajax add to cart
$(document).on('click', '.variations_form .wh-btn', function(e) {
e.preventDefault();
$variation_form = $(this).closest('.variations_form');
var var_id = $variation_form.find('input[name=variation_id]').val();
var product_id = $variation_form.find('input[name=product_id]').val();
var quantity = $variation_form.find('input[name=quantity]').val();
var letter = $variation_form.find('input[name=_wholesale_letter]').val();
var message = $variation_form.find('input[name=_wholesale_message]').val();
var rad = $variation_form.find('input[name=radio_field]:checked').val();
var file = $variation_form.find('input[name=file_field]').val();
//var file = $variation_form.find('input[name=file_field]').files[0].path;
//attributes = [];
$('.ajaxerrors').remove();
var item = {},
check = true;
variations = $variation_form.find('select[name^=attribute]');
/* Updated code to work with radio button - mantish - WC Variations Radio Buttons - 8manos */
if (!variations.length) {
variations = $variation_form.find('[name^=attribute]:checked');
}
/* Backup Code for getting input variable */
if (!variations.length) {
variations = $variation_form.find('input[name^=attribute]');
}
variations.each(function() {
var $this = $(this),
attributeName = $this.attr('name'),
attributevalue = $this.val(),
index,
attributeTaxName;
$this.removeClass('has-error');
if (attributevalue.length === 0) {
index = attributeName.lastIndexOf('_');
attributeTaxName = attributeName.substring(index + 1);
$this
//.css( 'border', '1px solid red' )
.addClass('required has-error')
//.addClass( 'barizi-class' )
.before('<div class="ajaxerrors"><p>OH No Please select ' + attributeTaxName + '</p></div>')
//check = false;
} else {
item[attributeName] = attributevalue;
}
});
if (!check) {
return false;
}
/* Validate for All the input Message field */
var itemMessages = {},
checkmsg = true;
messages = $variation_form.find('input[name=_message');
messages.each(function() {
var $this = $(this),
attributeName = $this.attr('name'),
attributevalue = $this.val(),
index,
attributeTaxName;
$this.removeClass('required wh-error');
if (attributevalue.length === 0) {
index = attributeName.lastIndexOf('_');
attributeTaxName = attributeName.substring(index + 1);
$this
.removeClass('wh-input')
.addClass('required wh-error')
.before('<div class="ajaxerrors"><p><span style="font-weight: bold;">REQUIRED!</span> Please Type Some Text or Number.</p></div>')
//checkmsg = false;
} else {
itemMessages[attributeName] = attributevalue;
$this.addClass('wh-input');
}
});
if (!checkmsg) {
return false;
}
/* Validate One Letter Input Field */
var itemLetter = {},
checkltr = true;
letterOne = $variation_form.find('input[name=_letter]');
letterOne.each(function() {
var $this = $(this),
attributeName = $this.attr('name'),
attributevalue = $this.val(),
index,
attributeTaxName;
$this.removeClass('required wh-error');
if (attributevalue.length === 0) {
index = attributeName.lastIndexOf('_');
attributeTaxName = attributeName.substring(index + 1);
$this
/* .css({
'border': '2px solid #a94442',
'box-shadow': 'inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483'
})*/
.removeClass('wh-input')
.addClass('required wh-error')
.before('<div class="ajaxerrors"><p><span style="font-weight: bold;">REQUIRED!</span> Please Type 1 Letter or Number.</p></div>')
//checkmsg = false;
} else {
itemLetter[attributeName] = attributevalue;
$this.addClass('wh-input');
}
});
if (!checkltr) {
return false;
}
//item = JSON.stringify(item);
//alert(item);
//return false;
// AJAX add to cart request
var $thisbutton = $(this);
if ($thisbutton.is('.variations_form .wh-btn')) {
$thisbutton.removeClass('added');
$thisbutton.addClass('loading');
$thisbutton.attr("disabled", "disabled");
var data = {
action: 'woocommerce_add_to_cart_wh_sh',
product_id: product_id,
quantity: quantity,
variation_id: var_id,
variation: item,
_letter: letter,
_message: message,
radio_field: rad,
file_field: file
};
$.each($thisbutton.data(), function(key, value) {
data[key] = value;
});
// Trigger event
$('body').trigger('adding_to_cart', [$thisbutton, data]);
// Ajax action
$.post(wc_add_to_cart_params.ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'), data, function(response) {
if (!response) {
return;
}
var this_page = window.location.toString();
this_page = this_page.replace('add-to-cart', 'added-to-cart');
if (response.error && response.product_url) {
window.location = response.product_url;
return;
}
if (wc_add_to_cart_params.cart_redirect_after_add === 'yes') {
window.location = wc_add_to_cart_params.cart_url;
return;
} else {
$thisbutton.removeClass('loading');
var fragments = response.fragments;
var cart_hash = response.cart_hash;
// Block fragments class
if (fragments) {
$.each(fragments, function(key) {
$(key).addClass('updating');
});
}
// Block widgets and fragments
$('.shop_table.cart, .updating, .cart_totals').fadeTo('400', '0.6').block({
message: null,
overlayCSS: {
opacity: 0.6
}
});
// Changes button classes
$thisbutton.addClass('added');
// View cart text
/* if ( ! wc_add_to_cart_params.is_cart && $thisbutton.parent().find( '.added_to_cart' ).size() === 0 ) {
$thisbutton.after( ' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>' );
}
// View cart text
if (!wc_add_to_cart_params.is_cart && $variation_form.find('.added_to_cart').length === 0) {
$thisbutton.after(' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>');
}
*/
// Replace fragments
if (fragments) {
$.each(fragments, function(key, value) {
$(key).replaceWith(value);
});
}
// Unblock
$('.widget_shopping_cart, .updating').stop(true).css('opacity', '1').unblock();
// Cart page elements
$('.shop_table.cart').load(this_page + ' .shop_table.cart:eq(0) > *', function() {
$('.shop_table.cart').stop(true).css('opacity', '1').unblock();
$(document.body).trigger('cart_page_refreshed');
});
$('.cart_totals').load(this_page + ' .cart_totals:eq(0) > *', function() {
$('.cart_totals').stop(true).css('opacity', '1').unblock();
});
// Trigger event so themes can refresh other areas
$(document.body).trigger('added_to_cart', [fragments, cart_hash, $thisbutton]);
}
})
.done(function(response) {
if ($variation_form.find('.added_to_cart').length === 0) {
$thisbutton.after(' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>');
}
$thisbutton.removeAttr("disabled", "disabled");
$thisbutton.removeClass('failed')
var quantity = $variation_form.find('input[name=quantity]').val("1");
var letter = $variation_form.find('input[name=_letter]').val("");
var message = $variation_form.find('input[name=_message]').val("");
var rad = $variation_form.find('input[name=radio_field]').val("Front Side");
})
.fail(function(response) {
setTimeout(function() {
$thisbutton.removeClass('loading');
$thisbutton.removeAttr("disabled", "disabled");
}, 2000);
$thisbutton.addClass('failed');
})
return false;
} else {
return true;
}
});
});
This page is only accessible to certain users, so it has different input fields, price than the single product page counterpart. Client don't like this page to be refreshed so I had to add AJAX, with the little knowledge I have. Now it's getting more complicated so please help me out.
Update 2021 - Still works perfectly on last WooCommerce version (5.1.x).
In your actual code, there is many mistakes as:
Repetitive hooked functions using the same hook, that need to be merged instead.
Deprecated hooked functions.
Not useful or not needed hooked functions.
Wrong or missing code related to file upload
Here is your revisited code (much more lighter, compact and complete):
// Display additional product fields (+ jQuery code)
add_action( 'woocommerce_before_add_to_cart_button', 'display_additional_product_fields', 9 );
function display_additional_product_fields(){
// Array of radio button options
$options = array( __("Front Side"), __("Back Side"), __("Both Sides") );
// Temporary styles
?>
<style>
.upload-logo a.button { padding: .3em .75em !important; }
.upload-logo a.button.on { background-color: #CC0000 !important; color: #FFFFFF !important; }
.upload-logo p span { display:inline-block; padding:0 8px 0 4px; }
</style><?php
// Html output ?>
<div class="upload-logo">
<p><strong><?php _e( "Add a Logo option"); ?>: </strong>
<?php _e( "Yes" ); ?>
<input type="hidden" name="upload_active" value="">
</p>
<div id="hidden-inputs" style="display:none">
<p><label for="radio_field"><?php
echo __( "Where you want the logo?" ) . ' <br>';
// Loop though each $options array
foreach( $options as $key => $option ) {
$atts = $key == 0 ? 'name="side_field" checked="checked"' : 'name="side_field"'; ?>
<input type="radio" <?php echo $atts; ?> value="<?php echo $option; ?>"><span> <?php echo $option . '</span> ';
}
?>
</label></p>
<p><label for="file_field"><?php echo __("Upload logo") . ': '; ?>
<input type='file' name='image' accept='image/*'>
</label></p>
</div>
</div><?php
// Javascript (jQuery) ?>
<script type="text/javascript">
jQuery( function($){
var a = '.upload-logo', b = a+' a.button',
c = a+' #hidden-inputs', d = a+' input[type=hidden]';
$(b).click(function(e){
e.preventDefault();
if( ! $(this).hasClass('on') ) {
$(this).addClass('on');
$(c).show();
$(d).val('1');
} else {
$(this).removeClass('on');
$(c).hide('fast');
$(d).val('');
}
});
});
</script>
<?php
}
// # ===> Manage the file upload <=== #
// Add custom fields data as the cart item custom data
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_fields_data_as_custom_cart_item_data', 10, 2 );
function add_custom_fields_data_as_custom_cart_item_data( $cart_item, $product_id ){
if( isset($_POST['upload_active']) && $_POST['upload_active'] && isset($_FILES['image']) ) {
$upload = wp_upload_bits( $_FILES['image']['name'], null, file_get_contents( $_FILES['image']['tmp_name'] ) );
$filetype = wp_check_filetype( basename( $upload['file'] ), null );
$upload_dir = wp_upload_dir();
$upl_base_url = is_ssl() ? str_replace('http://', 'https://', $upload_dir['baseurl']) : $upload_dir['baseurl'];
$base_name = basename( $upload['file'] );
$cart_item['custom_file'] = array(
'guid' => $upl_base_url .'/'. _wp_relative_upload_path( $upload['file'] ),
'file_type' => $filetype['type'],
'file_name' => $base_name,
'title' => preg_replace('/\.[^.]+$/', '', $base_name ),
'side' => isset( $_POST['side_field'] ) ? sanitize_text_field( $_POST['side_field'] ) : '',
'key' => md5( microtime().rand() ),
);
}
return $cart_item;
}
// Display custom cart item data in cart
add_filter( 'woocommerce_get_item_data', 'display_custom_item_data', 10, 2 );
function display_custom_item_data( $cart_item_data, $cart_item ) {
if ( isset( $cart_item['custom_file']['title'] ) ){
$cart_item_data[] = array(
'name' => __( 'Logo', 'woocommerce' ),
'value' => $cart_item['custom_file']['title']
);
}
if ( isset( $cart_item['custom_file']['side'] ) ){
$cart_item_data[] = array(
'name' => __( 'Side', 'woocommerce' ),
'value' => $cart_item['custom_file']['side']
);
}
return $cart_item_data;
}
// Save and display Logo data in orders and email notifications (everywhere)
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_field_update_order_item_meta', 20, 4 );
function custom_field_update_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset( $values['custom_file'] ) ){
$item->update_meta_data( __('Logo'), $values['custom_file']['title'] );
$item->update_meta_data( __('Side'), $values['custom_file']['side'] );
$item->update_meta_data( '_logo_file_data', $values['custom_file'] );
}
}
// Display a linked button + the link of the logo file in backend
add_action( 'woocommerce_after_order_itemmeta', 'backend_logo_link_after_order_itemmeta', 20, 3 );
function backend_logo_link_after_order_itemmeta( $item_id, $item, $product ) {
// Only in backend for order line items (avoiding errors)
if( is_admin() && $item->is_type('line_item') && $item->get_meta('_logo_file_data') ){
$file_data = $item->get_meta( '_logo_file_data' );
echo '<p>'.__("Open Logo") . '</p>';
echo '<p>Link: <textarea type="text" class="input-text" readonly>'.$file_data['guid'].'</textarea></p>';
}
}
This code goes in functions.php file of your active child theme (or active theme).
Tested in Woocommerce version 3.4.x and working with normal products (from all types)
Frontend: orders display (and email notifications):
Backend (Admin): Display on orders edit pages:
Related
How to make ajax adding an item to the cart — woocommerce?
Friends. Help me make ajax adding an item to the woocommerce cart. The code that I use was found on the Internet, it makes it possible to place buttons of variations on the product badge. enter image description here The code that outputs the buttons for each variation: ` function woocommerce_variable_add_to_cart(){ global $product, $post; $variations = find_valid_variations(); // Check if the special 'price_grid' meta is set, if it is, load the default template: if ( get_post_meta($post->ID, 'price_grid', true) ) { // Enqueue variation scripts wp_enqueue_script( 'wc-add-to-cart-variation' ); // Load the template wc_get_template( 'single-product/add-to-cart/variable.php', array( 'available_variations' => $product->get_available_variations(), 'attributes' => $product->get_variation_attributes(), 'selected_attributes' => $product->get_variation_default_attributes() ) ); return; } // Cool, lets do our own template! ?> <?php foreach ($variations as $key => $value) { if( !$value['variation_is_visible'] ) continue; ?> <?php $desc = $value['variation_description'] ?> <?php if($desc) { ?> <?php echo $desc ?> <?php }?> <?php if( $value['is_in_stock'] ) { ?> <form class="cart" action="<?php echo esc_url( $product->add_to_cart_url() ); ?>" method="post" enctype='multipart/form-data'> <?php if(!empty($value['attributes'])){ foreach ($value['attributes'] as $attr_key => $attr_value) { ?> <input type="hidden" name="<?php echo $attr_key?>" value="<?php echo $attr_value?>"> <?php } } ?> <button type="submit" class="single_add_to_cart_button btn btn-primary"><span class="glyphicon glyphicon-tag"></span>add to cart - <?php echo $attr_value?> - <?php echo $value['price_html'];?></button> <input type="hidden" name="variation_id" value="<?php echo $value['variation_id']?>" /> <input type="hidden" name="product_id" value="<?php echo esc_attr( $post->ID ); ?>" /> <input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $post->ID ); ?>" /> </form> <?php } else { ?> <p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p> <?php } ?> <?php } ?> <?php } function find_valid_variations() { global $product; $variations = $product->get_available_variations(); $attributes = $product->get_attributes(); $new_variants = array(); // Loop through all variations foreach( $variations as $variation ) { // Peruse the attributes. // 1. If both are explicitly set, this is a valid variation // 2. If one is not set, that means any, and we must 'create' the rest. $valid = true; // so far foreach( $attributes as $slug => $args ) { if( array_key_exists("attribute_$slug", $variation['attributes']) && !empty($variation['attributes']["attribute_$slug"]) ) { // Exists } else { // Not exists, create $valid = false; // it contains 'anys' // loop through all options for the 'ANY' attribute, and add each foreach( explode( '|', $attributes[$slug]['value']) as $attribute ) { $attribute = trim( $attribute ); $new_variant = $variation; $new_variant['attributes']["attribute_$slug"] = $attribute; $new_variants[] = $new_variant; } } } // This contains ALL set attributes, and is itself a 'valid' variation. if( $valid ) $new_variants[] = $variation; } return $new_variants; } ` I removed the redirect to the product card using the code, it remains to solve the issue with ajax add_filter( 'woocommerce_add_to_cart_redirect', 'wp_get_referer' );
Custom Meta Box Save_Post Callback not triggered in functions.php
child Theme, functions.php, I am creating a metabox. I have two text fields in a custom metabox. I need to save the fields anytime user clicks "update" or "publish" from the admin Add post. This meta box is allowed to appear in ally types of posts, including custom posts. I am running PHP7.3, running wordpress 5.3 I have tried to: 1) use others hooks like save_edit_post, admin_init, publish_post, etc. 2) to provide priority value to the add_Action 3) Reviewed HTTP post request to confirm the meta key-value pairs are getting passed - yes it is. 4) used get_post_meta() and $POST global variable to test if values are coming through - but couldn't verify. function add_taddressbox_address_meta_box() { add_meta_box( 'taddressbox_address_meta_box', // $id 'taddressbox Address', // $title 'show_taddressbox_address_meta_box', // $callback get_current_screen(), // $screen 'normal', // $context 'high' // $priority ); } function taddressbox_address_save_postdata($post_id, $post, $update) { //if this is post revision, then bail if (wp_is_post_revision( $post_id)) { return; } // if our current user can't edit this post, bail if( !current_user_can( 'edit_post' ) ) return; $lat_val = sanitize_text_field(get_post_meta($post_id, '_taddressbox_lng', true)); //get_post_meta($post->ID, 'taddressbox_lat', true); $lng_val = sanitize_text_field(get_post_meta($post_id, '_taddressbox_lng', true)); update_post_meta($post_id, '_taddressbox_lat', $lat_val); update_post_meta($post_id, '_taddressbox_lng', $lng_val); } function show_taddressbox_address_meta_box() { global $post; // $values = get_post_custom( $post->ID ); $lat = isset( $values['taddressbox_lat'] ) ? trim(esc_attr( $values['taddressbox_lat'][0] )) : '30'; $lng = isset( $values['taddressbox_lng'] ) ? trim(esc_attr( $values['taddressbox_lng'][0] )) : '69'; //$lat = '30'; //$lng ='69'; // $meta = get_post_meta( $post->ID, 'taddressbox_address', true ); ?> <input type="hidden" name="taddressbox_address_box_nonce" value="<?php echo wp_create_nonce( basename(__FILE__) ); ?>"> <!-- All fields will go here --> <div id="map" tabindex="0" style="position: relative;height:400px;margin:0; padding:0; display: block;"></div> <div id="taddressbox_latlng"> <label for"latitude">Latitude</label> <input type="text" id="taddressbox_lat" name="taddressbox_lat" value="<?php echo $lat; ?>"> <label for"longitude">Longitude</label> <input type="text" id="taddressbox_lng" name ="taddressbox_lng" value="<?php echo $lng; ?>"> </div> <script> <?php if ( trim($lat) == '' || trim($lng) =='' ) { ?> InitializetaddressboxMap(); <?php } else { ?> InitializetaddressboxMap(<?php echo $lat; ?>,<?php echo $lng; ?>); <?php } ?> </script> <?php }
You have to use $_POST[] to catch and save the form submitted code. I've fixed your code, feel free to use it. add_action( 'add_meta_boxes', 'add_taddressbox_address_meta_box' ); function add_taddressbox_address_meta_box() { add_meta_box( 'taddressbox_address_meta_box', // $id 'taddressbox Address', // $title 'show_taddressbox_address_meta_box', // $callback get_current_screen(), // $screen 'normal', // $context 'high' // $priority ); } add_action( 'save_post', 'taddressbox_address_save_postdata' ); function taddressbox_address_save_postdata( $post_id ) { //if this is post revision, then bail if (wp_is_post_revision( $post_id)) { return; } // if our current user can't edit this post, bail if( !current_user_can( 'edit_post' ) ) return; if ( ! isset( $_POST['my_lat_lang_box_nonce'] ) ) { return $post_id; } $nonce = $_POST['my_lat_lang_box_nonce']; // Verify that the nonce is valid. if ( ! wp_verify_nonce( $nonce, 'my_lat_lang_box' ) ) { return $post_id; } $lat_val = sanitize_text_field($_POST['taddressbox_lat']); $lng_val = sanitize_text_field($_POST['taddressbox_lng']); update_post_meta($post_id, '_taddressbox_lat', $lat_val); update_post_meta($post_id, '_taddressbox_lng', $lng_val); } function show_taddressbox_address_meta_box( $post ) { $lat = get_post_meta( $post->ID, '_taddressbox_lat', true ); $lng = get_post_meta( $post->ID, '_taddressbox_lng', true ); wp_nonce_field( 'my_lat_lang_box', 'my_lat_lang_box_nonce' ); ?> <!-- All fields will go here --> <div id="map" tabindex="0" style="position: relative;height:400px;margin:0; padding:0; display: block;"></div> <div id="taddressbox_latlng"> <label for"latitude">Latitude</label> <input type="text" id="taddressbox_lat" name="taddressbox_lat" value="<?php echo $lat; ?>"> <label for"longitude">Longitude</label> <input type="text" id="taddressbox_lng" name ="taddressbox_lng" value="<?php echo $lng; ?>"> </div> <script> <?php if ( trim($lat) == '' || trim($lng) =='' ) { ?> InitializetaddressboxMap(); <?php } else { ?> InitializetaddressboxMap(<?php echo $lat; ?>,<?php echo $lng; ?>); <?php } ?> </script> <?php }
How to add custom field to category and query it?
With this I add a custom field to a category: add_action ( 'edit_category_form_fields', function( $tag ){ $cat_title = get_term_meta( $tag->term_id, '_pagetitle', true ); ?> <tr class='form-field'> <th scope='row'><label for='cat_page_title'><?php _e('Category Page Title'); ?></label></th> <td> <input type='text' name='cat_title' id='cat_title' value='<?php echo $cat_title ?>'> <p class='description'><?php _e('Title for the Category '); ?></p> </td> </tr> <?php }); add_action ( 'edited_category', function() { if ( isset( $_POST['cat_title'] ) ) update_term_meta( $_POST['tag_ID'], '_pagetitle', $_POST['cat_title'] ); }); Then I try to add my own text with ajax: function data_person(){ $catname = $_POST['catName']; $surnameCat = $_POST["surnameCat"]; $cityCat = $_POST["cityCat"]; $catDob = $_POST["dobCat"]; $catBio = $_POST["catBio"]; $cat_ID = get_cat_ID( sanitize_title_for_query($catname) ); // Check if category exists if($cat_ID == 0) { $cat_name = $catname; $cat_sur = $surnameCat; $cat_city = $cityCat; $cat_dob = $catDob; $cat_bio = $catBio; $cat_slug = sanitize_title_with_dashes($cat_name); $my_cat = array( 'cat_name' => $cat_name, 'category_description' => $cat_bio, 'cat_title' => $cat_sur, 'category_nicename' => $cat_slug, 'category_parent' => 0 ); if( wp_insert_category( $my_cat ) ) { echo json_encode("Category added successfully"); } else { echo json_encode("That category already exists"); } } else { echo json_encode("That category already exists"); } exit; } but I am not sure how to add the text to the new created custom field, this isn't working: 'cat_title' => $cat_sur, as it isn't saving the value I am sending from the input field once I click. Basically what should I put instead of 'cat_title' => ? UPDATE This is the full code, so in function.php we have: add_action ( 'edit_category_form_fields', function( $tag ){ $cat_title = get_term_meta( $tag->term_id, '_pagetitle', true ); ?> <tr class='form-field'> <th scope='row'><label for='cat_page_title'><?php _e('Category Page Title'); ?></label></th> <td> <input type='text' name='cat_title' id='cat_title' value='<?php echo $cat_title ?>'> <p class='description'><?php _e('Title for the Category '); ?></p> </td> </tr> <?php }); add_action ( 'edited_category', function() { if ( isset( $_POST['cat_title'] ) ) update_term_meta( $_POST['tag_ID'], '_pagetitle', $_POST['cat_title'] ); }); add_action( 'wp_footer', 'ajax_Person' ); function ajax_Person() { ?> <script type="text/javascript"> jQuery("#saveperson").on("click", function(e){ e.preventDefault(); person(); }); function person(){ jQuery.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'post', data: { action: 'data_person', catName: jQuery('#nameCat').val(), catSurnam: jQuery('#surnameCat').val(), catCity: jQuery('#cityCat').val(), catDob: jQuery('#dobCat').val(), catBio: jQuery('#bioCat').val() }, success: function(data) { jQuery(".modal-body .help-text").html(data); } }); } </script> <?php } add_action('wp_ajax_data_person' , 'data_person'); add_action('wp_ajax_nopriv_data_person','data_person'); function data_person(){ $catname = $_POST['catName']; $surnameCat = $_POST["surnameCat"]; $cityCat = $_POST["cityCat"]; $catDob = $_POST["dobCat"]; $catBio = $_POST["catBio"]; $cat_ID = get_cat_ID( sanitize_title_for_query($catname) ); // Check if category exists if($cat_ID == 0) { $my_cat = array( 'cat_name' => $cat_name, 'category_description' => $cat_bio, 'category_nicename' => $cat_slug, 'category_parent' => 0 ); $cat_id = wp_insert_category( $my_cat ); if( ! is_wp_error( $cat_id ) && (int)$cat_id ) { // NOW, add the metadata... add_term_meta( $cat_id, '_pagetitle', $surnameCat ); echo json_encode("Category added successfully"); } else { echo json_encode("That category already exists"); } } exit; } And the html: <div class="col-xs-12"> <div class="add-pearson-form memory-form"> <div class="m-form-wrap"> <i class="fa fa-times-circle"></i> <div class="team_person"> <div class="form-group"> <div class="col-xs-12 col-sm-8 col-sm-offset-2"> <h4 class="text-center text-uppercase">aggiungi una persona</h4> <input type="text" class="form-control" placeholder="NOME"> <input type="text" class="form-control" placeholder="COGNOME"> <input type="text" class="form-control" placeholder="CITTA"> <input type="text" class="form-control pickdate" placeholder="DATA DI NASCITA"> <textarea class="form-control" id="froala-editor" placeholder=" type ricordo"></textarea> <div class="text-center"> inserisci persona </div> </div> </div> </div> </div> </div> </div>
The answer to your question is to use the add_term_meta function. Don't insert cat_title into the category - the wp_insert_category function doesn't accept / use that argument. Instead, get the category ID back from wp_insert_category, then use that ID to add the meta value. See your modified / simplified code below, with comments explaining changes: // no need to assign variables here, commented out and using originals below // $cat_name = $catname; // $cat_sur = $surnameCat; // $cat_city = $cityCat; // $cat_dob = $catDob; // $cat_bio = $catBio; // $cat_slug = sanitize_title_with_dashes($cat_name); $my_cat = array( 'cat_name' => $catname, 'category_description' => $catBio, // this is a _custom meta field_, so doesn't get inserted here... // 'cat_title' => $cat_sur, 'category_nicename' => sanitize_title_with_dashes($catname), 'category_parent' => 0 ); // get the category ID from the insert $cat_id = wp_insert_category( $my_cat ); if( ! is_wp_error( $cat_id ) && (int)$cat_id ) { // NOW, add the metadata... add_term_meta( $cat_id, '_pagetitle', $surnameCat ); echo json_encode("Category added successfully"); } else { echo json_encode("That category already exists"); }
':' shows up on mobile, but not on desktop - woocommerce/wordpress/php
Here is a picture of desktop and mobile, you can see there is a : in mobile that shouldn't be there. Any idea what the cause of it could be? Here is the template from the images - it uses code that falls outside of the scope of Wordpress because my client specifically requested I fix a problem this way, not because I think that it is a good idea to work outside of the scope of Wordpress :) <?php /** * Payment methods * * Shows customer payment methods on the account page. * * This template can be overridden by copying it to yourtheme/woocommerce/myaccount/payment-methods.php. * * HOWEVER, on occasion WooCommerce will need to update template files and you * (the theme developer) will need to copy the new files to your theme to * maintain compatibility. We try to do this as little as possible, but it does * happen. When this occurs the version of the template file will be bumped and * the readme will list any important changes. * * #see https://docs.woocommerce.com/document/template-structure/ * #author WooThemes * #package WooCommerce/Templates * #version 2.6.0 */ if ( ! defined( 'ABSPATH' ) ) { exit; } $current_user = wp_get_current_user(); $current_user_id = $current_user->ID; $customer_id = get_user_meta( $current_user_id, '_stripe_customer_id', true ); \Stripe\Stripe::setApiKey("xxx"); $customer = \Stripe\Customer::retrieve((string)$customer_id); $card_list = $customer->sources->all(["object" => "card"]); $show_table = true; if(isset($_POST['create_new_method'])) { $show_table = false; } $saved_methods = wc_get_customer_saved_methods_list( get_current_user_id() ); $has_methods = (bool) $saved_methods; $types = wc_get_account_payment_methods_types(); /*echo " **saved_methods: "; print_r($saved_methods); echo " **saved_methods length: "; count($saved_methods->cc); echo " **card list: "; print_r($card_list); echo " **card list length: ".count($card_list->data);*/ $just_added_method = false; if((empty($saved_methods) && count($card_list->data) > 0) || isset($_GET['added_card']) ) { $just_added_method = true; } do_action( 'woocommerce_before_account_payment_methods', $has_methods ); ?> <?php if ( ( ($has_methods || $just_added_method) && $show_table ) ) : ?> <?php if ( $has_methods && $show_table ) : ?> <table class="woocommerce-MyAccount-paymentMethods shop_table shop_table_responsive account-payment-methods-table"> <thead> <tr> <?php foreach ( wc_get_account_payment_methods_columns() as $column_id => $column_name ) : ?> <th class="woocommerce-PaymentMethod woocommerce-PaymentMethod--<?php echo esc_attr( $column_id ); ?> payment-method-<?php echo esc_attr( $column_id ); ?>"><span class="nobr"><?php echo esc_html( $column_name ); ?></span></th> <?php endforeach; ?> </tr> </thead> <?php foreach ( $saved_methods as $type => $methods ) : ?> <?php foreach ( $methods as $method ) : ?> <tr class="payment-method<?php echo ! empty( $method['is_default'] ) ? ' default-payment-method' : '' ?>"> <?php foreach ( wc_get_account_payment_methods_columns() as $column_id => $column_name ) : ?> <td class="woocommerce-PaymentMethod woocommerce-PaymentMethod--<?php echo esc_attr( $column_id ); ?> payment-method-<?php echo esc_attr( $column_id ); ?>" data-title="<?php echo esc_attr( $column_name ); ?>"> <?php if ( has_action( 'woocommerce_account_payment_methods_column_' . $column_id ) ) { do_action( 'woocommerce_account_payment_methods_column_' . $column_id, $method ); } elseif ( 'method' === $column_id ) { if ( ! empty( $method['method']['last4'] ) ) { /* translators: 1: credit card type 2: last 4 digits */ echo sprintf( __( '%1$s ending in %2$s', 'woocommerce' ), esc_html( wc_get_credit_card_type_label( $method['method']['brand'] ) ), esc_html( $method['method']['last4'] ) ); } else { echo esc_html( wc_get_credit_card_type_label( $method['method']['brand'] ) ); } } elseif ( 'expires' === $column_id ) { echo esc_html( $method['expires'] ); } elseif ( 'actions' === $column_id ) { foreach ( $method['actions'] as $key => $action ) { echo '' . esc_html( $action['name'] ) . ' '; } } ?> </td> <?php endforeach; ?> </tr> <?php endforeach; ?> <?php endforeach; ?> <?php if ($just_added_method && $show_table && empty($saved_methods)) : ?> <?php foreach ( $card_list->data as $added_card ) : ?> <tr class="payment-method"> <?php foreach ( wc_get_account_payment_methods_columns() as $column_id => $column_name ) : ?> <td class="woocommerce-PaymentMethod woocommerce-PaymentMethod--<?php echo esc_attr( $column_id ); ?> payment-method-<?php echo esc_attr( $column_id ); ?>" data-title="<?php echo esc_attr( $column_name ); ?>"> <?php if ( has_action( 'woocommerce_account_payment_methods_column_' . $column_id ) ) { do_action( 'woocommerce_account_payment_methods_column_' . $column_id, $method ); } elseif ( 'method' === $column_id ) { $last4 = $added_card->last4; $brand = $added_card->brand; if ( ! empty( $last4 ) ) { /* translators: 1: credit card type 2: last 4 digits */ echo sprintf( __( '%1$s ending in %2$s', 'woocommerce' ), esc_html( wc_get_credit_card_type_label( $brand ) ), esc_html( $last4 ) ); } else { echo esc_html( wc_get_credit_card_type_label( $brand ) ); } } elseif ( 'expires' === $column_id ) { echo esc_html( $added_card['exp_month']."/".substr($added_card['exp_year'], 2) ); } elseif ( 'actions' === $column_id ) { ?> <button class="woocommerce-Button woocommerce-Button--alt button alt" id="delete_card" style="color: white!important" name="delete_card" onClick="location.href='https://www.grahmlux.com/wp-content/themes/betheme/includes/delete_payment_method.php?id=<?php echo $added_card->id; ?>&user_id=<?php echo $current_user_id; ?>'">Delete</button> <?php if($customer->default_source != $added_card->id) { ?> <button class="woocommerce-Button woocommerce-Button--alt button alt" id="make_default" style="color: white!important" name="make_default" onClick="location.href='https://www.grahmlux.com/wp-content/themes/betheme/includes/make_default.php?id=<?php echo $added_card->id; ?>&user_id=<?php echo $current_user_id; ?>'">Make default</button> <?php } ?> <?php } ?> </td> <?php endforeach; ?> </tr> <?php endforeach; ?> <?php endif; ?> <?php if ($just_added_method && $show_table && !empty($saved_methods)) { $added_card = $card_list->data[count($card_list) - 1] ?> <tr class="payment-method"> <?php foreach ( wc_get_account_payment_methods_columns() as $column_id => $column_name ) : ?> <td class="woocommerce-PaymentMethod woocommerce-PaymentMethod--<?php echo esc_attr( $column_id ); ?> payment-method-<?php echo esc_attr( $column_id ); ?>" data-title="<?php echo esc_attr( $column_name ); ?>"> <?php if ( has_action( 'woocommerce_account_payment_methods_column_' . $column_id ) ) { do_action( 'woocommerce_account_payment_methods_column_' . $column_id, $method ); } elseif ( 'method' === $column_id ) { $last4 = $added_card->last4; $brand = $added_card->brand; if ( ! empty( $last4 ) ) { /* translators: 1: credit card type 2: last 4 digits */ echo sprintf( __( '%1$s ending in %2$s', 'woocommerce' ), esc_html( wc_get_credit_card_type_label( $brand ) ), esc_html( $last4 ) ); } else { echo esc_html( wc_get_credit_card_type_label( $brand ) ); } } elseif ( 'expires' === $column_id ) { echo esc_html( $added_card['exp_month']."/".substr($added_card['exp_year'], 2) ); } elseif ( 'actions' === $column_id ) { ?> <button class="woocommerce-Button woocommerce-Button--alt button alt" id="delete_card" style="color: white!important" name="delete_card" onClick="location.href='https://www.grahmlux.com/wp-content/themes/betheme/includes/delete_payment_method.php?id=<?php echo $added_card->id; ?>&user_id=<?php echo $current_user_id; ?>'">Delete</button> <?php if($customer->default_source != $added_card->id) { ?> <button class="woocommerce-Button woocommerce-Button--alt button alt" id="make_default" style="color: white!important" name="make_default" onClick="location.href='https://www.grahmlux.com/wp-content/themes/betheme/includes/make_default.php?id=<?php echo $added_card->id; ?>&user_id=<?php echo $current_user_id; ?>'">Make default</button> <?php } ?> <?php } ?> </td> <?php endforeach; ?> </tr> <?php } ?> </table> <form action="" method="post"> <input class="woocommerce-Button woocommerce-Button--alt button alt" style="background-color: #88d651!important;" name="create_new_method" type="submit" value="Add payment method" /> </form> <?php endif; ?> <?php else : $current_user = wp_get_current_user(); $current_user_id = $current_user->ID; $customer_id = get_user_meta( $current_user_id, '_stripe_customer_id', true ); \Stripe\Stripe::setApiKey("xxx"); if($customer_id == NULL) { echo 'Make your first purchase to activate this feature - Shop Now'; //die(); } else { $customer = \Stripe\Customer::retrieve((string)$customer_id); } ?> <?php if(count($card_list->data) == 0) { ?> <p class="woocommerce-Message woocommerce-Message--info woocommerce-info"><?php esc_html_e( 'No saved methods found.', 'woocommerce' ); ?></p> <?php } ?> <!--<form action="https://www.grahmlux.com/wp-content/themes/betheme/includes/add_payment_method.php" method="post" id="add_payment_method">--> <form action="https://www.grahmlux.com/wp-content/themes/betheme/includes/add_payment_method.php" method="post" id="add_payment_method"> <div class="form-row"> <label for="card-element"> Credit or Debit Card (Secured By Stripe) </label> <div id="card-number" style="display: inline-block; width: 180px"></div> <div id="card-expiry" style="display: inline-block; width: 60px"></div> <div id="card-cvc" style="display: inline-block; width: 50px"></div> <!-- Used to display Element errors. --> <div id="card-errors" role="alert"></div> <button type="submit" class="woocommerce-Button woocommerce-Button--alt button alt" id="place_order" style="color: white!important" value="<?php esc_attr_e( 'Add payment method', 'woocommerce' ); ?>"><?php esc_html_e( 'Add payment method', 'woocommerce' ); ?></button> </div> </form> <script> var style = { base: { color: '#ffffff', fontSize: '14px', fontSmoothing: 'antialiased', '::placeholder': { color: '#ccc', }, iconColor: "#fff" }, invalid: { color: '#e5424d', ':focus': { color: '#303238', }, }, }; var stripe = Stripe('pk_test_TpmyYk1TnhrxPqNpImYwjyap'); var elements = stripe.elements(); var cardNumber = elements.create('cardNumber', { placeholder: 'Add Card Number Here', style: style }); var cardExpiry = elements.create('cardExpiry', { style: style }); var cardCvc = elements.create('cardCvc', { style: style }); window.mobilecheck = function() { var check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); return check; }; if(mobilecheck()) { cardNumber.mount('#Content > div > div > div > div.section.mcb-section.hide-desktop > div > div > div > div > div > div > div > form > div.form-row >div#card-number'); cardExpiry.mount('#Content > div > div > div > div.section.mcb-section.hide-desktop > div > div > div > div > div > div > div > form > div.form-row >div#card-expiry'); cardCvc.mount('#Content > div > div > div > div.section.mcb-section.hide-desktop > div > div > div > div > div > div > div > form > div.form-row >div#card-cvc'); } else { cardNumber.mount('#Content > div > div > div > div.section.mcb-section.hide-tablet.hide-mobile > div > div > div > div > div > div > div > form > div.form-row > div#card-number'); cardExpiry.mount('#Content > div > div > div > div.section.mcb-section.hide-tablet.hide-mobile > div > div > div > div > div > div > div > form > div.form-row > div#card-expiry'); cardCvc.mount('#Content > div > div > div > div.section.mcb-section.hide-tablet.hide-mobile > div > div > div > div > div > div > div > form > div.form-row > div#card-cvc'); } cardNumber.addEventListener('change', function(event) { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); var stop = 0; // Create a token or display an error when the form is submitted. var form = document.getElementById('add_payment_method'); form.addEventListener('submit', function(event) { event.preventDefault(); stripe.createToken(cardNumber).then(function(result) { if (result.error) { // Inform the customer that there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { if(stop == 0) { console.log("inside stop token from being stored"); // Send the token to your server. stripeTokenHandler(result.token); stop = 1; } else { stop = 0 } } }); }); function delete_cookie( name ) { document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; } function createCookie(name,value) { delete_cookie("stripe_token"); var date = new Date(); date.setTime(date.getTime()+1000); var expires = "; expires="+date.toGMTString(); document.cookie = name+"="+value+expires+"; path=/; domain=.grahmlux.com"; //document.cookie = name+"="+value+expires+"; path=/"; } function createUserIDCookie(name,value) { document.cookie = name+"="+value+""+"; path=/; domain=.grahmlux.com"; //document.cookie = name+"="+value+""+"; path=/"; } function stripeTokenHandler(token) { var current_user_id = <?php echo $current_user_id; ?> console.log("current_user_id:", current_user_id); //MUST BE THIS ORDER BECAUSE OF DELETE_COOKIE createUserIDCookie("user_id", current_user_id); createCookie("stripe_token", token); var form = document.getElementById('add_payment_method'); form.submit(); } </script> <?php endif; ?> <?php do_action( 'woocommerce_after_account_payment_methods', $has_methods ); ?> Anyone see any typos/anything that could be causing this to happen on mobile and not on desktop?
I needed to edit the css, the : was in a ::before tag.
Quantity Input as Dropdown on Cart Page Only
I am trying to implement two different kinds of quantity input for my WooCommerce store. On the cart page, I'm using a field with plus and minus buttons to change the value. Here's the code: <?php /** * Product quantity inputs * * This template can be overridden by copying it to yourtheme/woocommerce/global/quantity-input.php. * * HOWEVER, on occasion WooCommerce will need to update template files and you * (the theme developer) will need to copy the new files to your theme to * maintain compatibility. We try to do this as little as possible, but it does * happen. When this occurs the version of the template file will be bumped and * the readme will list any important changes. * * #see https://docs.woocommerce.com/document/template-structure/ * #author WooThemes * #package WooCommerce/Templates * #version 2.5.0 */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } ?> <div class="quantity"> <button class="qty-minus" type="button" value=""></button> <input class="qty-input" type="number" step="<?php echo esc_attr( $step ); ?>" min="<?php echo esc_attr( $min_value ); ?>" max="<?php echo esc_attr( $max_value ); ?>" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" readonly title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="input-text qty text" size="4" /> <button class="qty-plus" type="button" value=""></button> </div> <script type="text/javascript"> jQuery(document).ready(function($){ $('.quantity').on('click', '.qty-plus', function(e) { $input = $(this).prev('input.qty-input'); var val = parseInt($input.val()); $input.val( val+1 ).change(); }); $('.quantity').on('click', '.qty-minus', function(e) { $input = $(this).next('input.qty-input'); var val = parseInt($input.val()); if (val > 0) { $input.val( val-1 ).change(); } }); }); </script> This is working perfectly. However, the quantity field on the cart page inherits this format as well. I'd like it to be a selectable dropdown instead. I tried using this code on the cart page: <?php $defaults = array( 'max_value' => apply_filters( 'woocommerce_quantity_input_max', '', $product ), 'min_value' => apply_filters( 'woocommerce_quantity_input_min', '', $product ), 'step' => apply_filters( 'woocommerce_quantity_input_step', '1', $product ), ); if ( ! empty( $defaults['min_value'] ) ) $min = $defaults['min_value']; else $min = 1; if ( ! empty( $defaults['max_value'] ) ) $max = $defaults['max_value']; else $max = 10; if ( ! empty( $defaults['step'] ) ) $step = $defaults['step']; else $step = 1; ?> <div class="quantity_select"> <select name="<?php echo esc_attr( $input_name ); ?>" title="<?php _ex( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="qty"> <?php for ( $count = $min; $count <= $max; $count = $count+$step ) { if ( $count == $input_value ) $selected = ' selected'; else $selected = ''; echo '<option value="' . $count . '"' . $selected . '>' . $count . '</option>'; } ?> The dropdown displays and is selectable, but if I choose a different quantity and then click "Update Cart", the quantity stays the same. It isn't changing. How can I do this? Thank you!
I've added the is_cart() condition to the quantity-input.php template to distinguish between where to use the buttons and where to use the select. Cleaned up a few other things, and it seems to work fine for me. Granted, I am using WC2.7-beta-1, so I don't know if that is having an effect. if( is_cart() ){ $min_value = $min_value ? $min_value : 0; $max_value = $max_value ? $max_value : 10; ?> <div class="quantity quantity_select"> <select name="<?php echo esc_attr( $input_name ); ?>" title="<?php _ex( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="qty"> <?php for ( $count = $min_value; $count <= $max_value; $count = $count+$step ) { echo '<option value="' . esc_attr( $count ) . '"' . selected( $count, $input_value, false ) . '>' . $count . '</option>'; } } else { ?> <div class="quantity"> <button class="qty-minus" type="button" value="">-</button> <input class="qty-input" type="number" step="<?php echo esc_attr( $step ); ?>" min="<?php echo esc_attr( $min_value ); ?>" max="<?php echo esc_attr( $max_value ); ?>" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" readonly title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="input-text qty text" size="4" /> <button class="qty-plus" type="button" value="">+</button> </div> <script type="text/javascript"> jQuery(document).ready(function($){ $('.quantity').on('click', '.qty-plus', function(e) { $input = $(this).prev('input.qty-input'); var val = parseInt($input.val()); $input.val( val+1 ).change(); }); $('.quantity').on('click', '.qty-minus', function(e) { $input = $(this).next('input.qty-input'); var val = parseInt($input.val()); if (val > 0) { $input.val( val-1 ).change(); } }); }); </script> <?php }
I came up with a solution myself. I added the following in my cart.php template where I wanted the quantity dropdown to show up: <?php if ($_product->is_sold_individually()) { $product_quantity = sprintf('1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key); } else { global $product; $defaults = array( 'input_name' => "cart[{$cart_item_key}][qty]", 'input_value' => $cart_item['quantity'], 'max_value' => apply_filters( 'woocommerce_quantity_input_max', '', $product ), 'min_value' => apply_filters( 'woocommerce_quantity_input_min', '', $product ), 'step' => apply_filters( 'woocommerce_quantity_input_step', '1', $product ), 'style' => apply_filters( 'woocommerce_quantity_style', 'float:left; margin-right:10px;', $product ) ); if (!empty($defaults['min_value'])) $min = $defaults['min_value']; else $min = 1; if (!empty($defaults['max_value'])) $max = $defaults['max_value']; else $max = 20; if (!empty($defaults['step'])) $step = $defaults['step']; else $step = 1; $options = ''; for($count = $min;$count <= $max;$count = $count+$step){ if($count == $cart_item['quantity']) $selected="selected=selected"; else $selected=''; $options .= '<option value="' . $count . '" '.$selected.'>' . $count . '</option>'; } echo '<select name="' . esc_attr( $defaults['input_name'] ) . '" title="' . _x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) . '" class="qty">' . $options . '</select>'; }?></div> It's fully functional. I now have a quantity input with plus/minus buttons on my single product page and a selectable dropdown on my cart page.