The context:
On my website users can customize clothing products. Along the customer funnel, it is asked to the user to input a quantity. This quantity is then used when our team receives the order to generate a quote. Nevertheless, it appears that the quantity is not stored as it always returns 1, even when the user inputs another number e.g. 100. I cannot find a way to solve this.
Below you will find code parts that include the quantity dimension. If you see any corrections to be made feel free to mention them.
add_filter( 'wc_add_to_cart_message_html', 'epopey_wc_add_to_cart_message_html', 10, 3);
function epopey_wc_add_to_cart_message_html ( $message, $products, $show_qty ){
$titles = array();
if ( ! is_array( $products ) ) {
$products = array( $products => 1 );
}
if ( ! $show_qty ) {
$products = array_fill_keys( array_keys( $products ), 1 );
}
foreach ( $products as $product_id => $qty ) {
/* translators: %s: product name */
$titles[] = apply_filters( 'woocommerce_add_to_cart_qty_html', ( $qty > 1 ? absint( $qty ) . ' × ' : '' ), $product_id ) . apply_filters( 'woocommerce_add_to_cart_item_name_in_quotes', sprintf( _x( '“%s”', 'Item name in quotes', 'woocommerce' ), strip_tags( get_the_title( $product_id ) ) ), $product_id );
$count += $qty;
}
$titles = array_filter( $titles );
Backorder notification
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
echo '<p class="backorder_notification">' . esc_html__( 'Available on backorder', 'norebro' ) . '</p>';
}
?>
</h4>
</td>
<td class="product-quantity" data-title="<?php esc_html_e( 'Quantity', 'norebro' ); ?>">
<?php
if ( $_product->is_sold_individually() ) {
$product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
} else {
$product_quantity = woocommerce_quantity_input( array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->backorders_allowed() ? '' : $_product->get_stock_quantity(),
'min_value' => '0'
), $_product, false );
}
echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item );
?>
</td>
email details to customer
<td class="td" style="text-align:<?php echo esc_attr( $text_align ); ?>; vertical-align:middle; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;">
<?php
$qty = $item->get_quantity();
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
if ( $refunded_qty ) {
$qty_display = '<del>' . esc_html( $qty ) . '</del> <ins>' . esc_html( $qty - ( $refunded_qty * -1 ) ) . '</ins>';
} else {
$qty_display = esc_html( $qty );
}
echo wp_kses_post( apply_filters( 'woocommerce_email_order_item_quantity', $qty_display, $item ) );
?>
</td>
order details
<td class="product-quantity">
<?php echo apply_filters( 'woocommerce_order_item_quantity_html', ' <strong class="product-quantity">' . sprintf( '%s', $item->get_quantity() ) . '</strong>', $item ); ?>
</td>
</tr>
<?php if ( $show_purchase_note && $purchase_note ) : ?>
<tr class="product-purchase-note">
<td colspan="2"><?php echo wpautop( do_shortcode( wp_kses_post( $purchase_note ) ) ); ?></td>
Table with order details
<table class="woo-my-orders-table woo-details woo-my-content">
<thead>
<tr>
<th class="product-name"><?php esc_html_e( 'Product', 'norebro' ); ?></th>
<th class="product-quantity"><?php esc_html_e( 'Quantity', 'norebro' ); ?></th>
</tr>
</thead>
<tbody>
<?php
foreach( $order->get_items() as $item_id => $item ) {
$product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item );
wc_get_template( 'order/order-details-item.php', array(
'order' => $order,
'item_id' => $item_id,
'item' => $item,
'show_purchase_note' => $show_purchase_note,
'purchase_note' => $product ? get_post_meta( $product->get_id(), '_purchase_note', true ) : '',
'product' => $product,
) );
}
?>
<?php do_action( 'woocommerce_order_items_table', $order ); ?>
</tbody>
</table>
Congrats if you read until here, hope there is enough details. Thanks for your time and help.
Edit #1
Could the below code lines be a starting point to solve the problem ?
HTML
<div type="submit" class="wc-proceed-to-checkout" onClick="quantitySubmit(this.form)">
Valider le devis
JS
function quantitySubmit(form){
return (form.submit()){
window.location.href = "https://epopey.co/validation-du-devis/"
}
else {
text = "Please input a number"
}
}
The page that allows a change in quantity isn't updating the cart when it moves to the validate quote page. The button that was added to link to that page doesn't first perform the woo commerce cart update. See below:
The input of type submit must be "clicked" so the page can post back to itself and update the cart before the browser is redirected to the new page.
I'd recommend a simple javascript function in the onclick attribute of the div (class = wc-proceed-to-checkout) that submits the form and returns true/false on success/failure and allows redirection to "https://epopey.co/validation-du-devis/" for success and gives whatever error message you decide on failure.
To redirect in JS: https://www.w3schools.com/howto/howto_js_redirect_webpage.asp
If you need help writing the javascript to submit your form and handle the return value, search for answers on this site, I know they exist/also on Google.
There are numerous other ways to solve this as well - hard to give a best practice answer without knowing your code base/the structure of the theme. Hopefully identifying the problem is enough for you to solve on your own.
TLDR; your validate quote button overrides a default submission button to update the cart with increased/decreased quantities. Make sure the form on this page posts before the page is redirected to the next, or you'll lose the changed quantities.
Related
I'm using the code below to add three buttons to the WooCommerce checkout page so customers can leave a donation. It's working as it should be, but it would be great if I can highlight one of the buttons when a customer adds a donation to their cart and disable the other two.
Any thoughts on how I can get this to work?
add_action( 'woocommerce_review_order_before_submit', 'charity_checkout_add_on', 9999 );
function charity_checkout_add_on() {
$product_ids = array( 59355 );
$in_cart = false;
foreach( WC()->cart->get_cart() as $cart_item ) {
$product_in_cart = $cart_item['variation_id'];
if ( in_array( $product_in_cart, $product_ids ) ) {
$in_cart = true;
break;
}
}
if ( ! $in_cart ) {
echo '<div id="charity-donation">';
echo '<h6>Heading text</h6>';
echo '<p>Explanation</p>';
echo '<a class="charity-button" href="?add-to-cart=59356">€0,50</a><a class="charity-button" href="?add-to-cart=59357">€1,00</a><a class="charity-button last" href="?add-to-cart=59358">€2,50</a>';
echo '</div>';
}
}
Instead of hard-coding the HTML for the buttons you can loop over the $product_ids array to fetch and build up the HTML dynamically. This will work for both simple and variable products. You should always escape these values where possible: see https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/
You could then simply add a css class to the button if the product is in the cart by comparing its ID against any of the IDs in the cart.
Issues with add to cart in URL
If you don't redirect to the cart page after the product has been added, when the checkout refreshes the ?add-to-cart=ID query parameter will remain in the URL. This means that if you refresh the checkout page, the product will be added again. To solve this, either tick "Redirect to the basket page after successful addition" in Woocommerce Settings > Products > General or change the add-t-cart url to something like yourdomain.com/cart/?add-to-cart=ID
Try:
add_action( 'woocommerce_review_order_before_submit', 'charity_checkout_add_on', 20 );
function charity_checkout_add_on() {
$product_ids = array( 59356, 59357, 59358 );
$products_in_cart = array();
$button_data = array();
// Gather product cart items in array
foreach( WC()->cart->get_cart() as $cart_item ) {
$cart_product = $cart_item['data'];
$products_in_cart[] = $cart_product->get_id();
}
// Dynamically generate buttons
$button_html = '';
$last_button = end( $product_ids );
foreach( $product_ids as $product_id ) {
if( $product = wc_get_product( $product_id ) ) {
$in_cart = ( in_array( $product->get_id(), $products_in_cart ) ) ? true : false;
$button_classes = 'charity-button';
if( $in_cart ) {
$button_classes.= ' disabled';
}
if( $product_id === $last_button ) {
$button_classes.= ' last';
}
$button_html .= sprintf(
'<a class="%s"%s>%s</a>',
esc_attr( $button_classes ),
( $in_cart ) ? '' : esc_url( 'href="?add-to-cart=' . $product->get_id() . '"' ),
esc_html( get_woocommerce_currency_symbol() . $product->get_price() )
);
};
}
?>
<h4>Make a Donation?</h4>
<div id="charity-donation">
<h6>Heading text</h6>
<p>Explanation</p>
<?php echo $button_html; ?>
</div>
<?php
}
Your css class then could be something like:
.charity-button.disabled {
cursor: not-allowed;
opacity: 0.5;
}
So I have this widget that I coded base on wordpress standard. I declared a sort of variables to be use both backend and frontend purposes.
public function widget( $args, $instance ) {
global $post;
$sid = $instance['id'];
$name = $instance['name'];
$args = array( 'post_type' => 'content_manager','post_id' => $sid);
$query = new WP_Query( $args );
echo $args['before_widget'];
echo $args['after_widget'];
}
public function form( $instance ) {
global $post;
$args = array( 'post_type' => 'content_manager'); ....
$loop = new WP_Query( $args );
$title = ! empty( $instance['title'] ) ? $instance['title'] : esc_html__( 'New title', 'text_domain' );
$sid = ! empty( $instance['id'] ) ? $instance['id'] : esc_html__( 'New ID', 'text_domain' );
$name = ! empty( $instance['name'] ) ? $instance['name'] : esc_html__( 'Empty Content', 'text_domain' );
I am using the variables to get the values in javascript
<script>
function defineValue(sel)
{
var title = sel.options[sel.selectedIndex].text;
var id = sel.options[sel.selectedIndex].value;
document.getElementById("<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>").value = title;
document.getElementById("<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>").value = id;
document.getElementById("<?php echo esc_attr( $this->get_field_name( 'name' ) ); ?>").value = title;
}
</script>
When I load the widget, the inputs and other options displays the names and IDs but in Javascript returns empty unless If I save it first.
I tried to test it
<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>
and this is the result
widget-content-loader-__i__-id
Why is that happen?
Notes:
First Inputs and other elements have ids and other attributes from that variables when I check in the DOM
<input class="widefat" name="widget-content-loader[21][title]" id="widget-content-loader-21-title" value="New title" type="text">
From this this script:
<input
class="widefat"
name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
type="text"
id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
value="<?php echo esc_attr( $title ); ?>">
Thanks in advance
Javascript cant get value unless it is loaded into DOM,
Make sure that the elements are loaded before calling definevalue()
I Developing one project and I stuck in small thing which is very small for PHP Expert :D Which i'm not
I'm Trying to make Dropdown list of Custom taxonomies which work on select go to that Custom taxonomies page.
But After lot of search I found Solution But not doing action to go to the selected Custom taxonomies
First I found
<?php wp_dropdown_categories( 'taxonomy=my_custom_taxonomy' ); ?>
Second I found
function fjarrett_custom_taxonomy_dropdown( $taxonomy ) {
$terms = get_terms( $taxonomy );
if ( $terms ) {
printf( '<select name="%s" class="postform">', esc_attr( $taxonomy ) );
foreach ( $terms as $term ) {
printf( '<option value="%s">%s</option>', esc_attr( $term->slug ), esc_html( $term->name ) );
}
print( '</select>' );
}
}
Which I can use when I insert in any page code billow
<?php fjarrett_custom_taxonomy_dropdown( 'my_custom_taxonomy' ); ?>
Credit
https://frankiejarrett.com/2011/09/create-a-dropdown-of-custom-taxonomies-in-wordpress-the-easy-way/
BUT I DON'T KNOW NOW HOW I GONNA MAKE IT WORKING
Hope you can help me to find solution that from above any one solution can I able to make select and go thing.
Thanks in advance
POSSIBLE ANSWER - 1
I Found Possible Answer
<form id="category-select" class="category-select" action="<?php echo esc_url( home_url( '/' ) ); ?>" method="get">
<?php
$args = array(
'show_option_none' => __( 'Select category' ),
'show_count' => 1,
'orderby' => 'name',
'name' => 'cat',
'echo' => 0,
'taxonomy' => 'MyCustomTaxonomys',
'value_field' => 'slug'
);
?>
<?php $select = wp_dropdown_categories( $args ); ?>
<?php $replace = "<select$1 onchange='return this.form.submit()'>"; ?>
<?php $select = preg_replace( '#<select([^>]*)>#', $replace, $select ); ?>
<?php echo $select; ?>
<noscript>
<input type="submit" value="View" />
</noscript>
</form>
It Give me URL
www.website.com/?cat=xxx where xxx is my custom taxonomy
But I Want URL
www.website.com/cat/xxx where xxx is my custom taxonomy
Is it possible?
You
could use something like this :
<?php
function fjarrett_custom_taxonomy_dropdown( $taxonomy ) {
$terms = get_terms( $taxonomy );
if ( $terms ) {
printf( '<select name="%s" class="postform">', esc_attr( $taxonomy ) );
foreach ( $terms as $term ) {
printf( '<option value="%s" data-location="%s">%s</option>', esc_attr( $term->slug ), get_term_link(term_id), esc_html( $term->name ) );
}
print( '</select>' );
}
}
?>
Then use your javascript code to redirect depending on the value of the attribute data-location
I did it this way like you say with PHP with wordpres:
<?php function click_taxonomy_dropdown($taxonomy, $title) { ?>
<select name="<?php echo $taxonomy;?>" id="<?php echo $taxonomy;?>">
<option value="-1"><?php echo $title;?></option>
<?php
$terms = get_terms($taxonomy);
foreach ($terms as $term) {
$link = get_term_link( $term, $taxonomy );
if($term->parent == 0){
printf( '<option class="level-1" value="'.$link.'">%s</option>', $term->name );
}
}
echo '</select>';
?>
<?php } ?>
And then with JS:
var dropdown1=document.getElementById("yourtaxonomy");
function onCatChange1(){
if(dropdown1.options[dropdown1.selectedIndex].value>"")
location.href=dropdown1.options[dropdown1.selectedIndex].value
}
The JS just get the ID of your select and then go to value when options are selected
AT End I Found One Alternate Working Solution Writing here so it will help someone needful
<?php
$categories = get_categories('taxonomy=xxxx');
$select = "<select name='' id='cat' class='postform'>n";
$select.= "<option value='-1'>Select category</option>n";
foreach($categories as $category){
if($category->count > 0){
$select.= "<option value='".$category->slug."'>".$category->name."
</option>";
}
}
$select.= "</select>";
echo $select;
?>
<script type="text/javascript">
<!--
var dropdown = document.getElementById("cat");
function onCatChange() {
if (dropdown.options[dropdown.selectedIndex].value != -1) {
location.href = "<?php echo home_url();?>/yyyy/" + dropdown.options[dropdown.selectedIndex].value + "/";
}
}
dropdown.onchange = onCatChange;
-->
</script>
JUST SET Proper XXXX and YYYY Value and solve.
Credit: John B. Hartley
http://www.johnbhartley.com/2012/custom-taxonomy-category-dropdown/
Again Thank you all for your efforts
So my website lists upcoming film screenings in my area.
I'm using the ACF date time picker to only show posts/film screenings that are in the future in the wordpress loop.
I have tags filtering the results dynamically using ajax (thanks to https://www.bobz.co/ajax-filter-posts-tag/) except there are tags that aren't relevant to the results because they belong to posts that are older than the current date (past screenings).
*For example on the website, the 'animated film festival' is still coming up with the other tags.
I don't know if it's possible to delete a posts tags with PHP (within the post template while it loops through other posts) - and to delete the posts tags if the ACF date time field for that post is older than the current date.
I haven't found much luck googling this and I am a bit of a noob so...
This is my site: http://pigcine.pamrosel.com/
This is what I'm doing in my functions.php file at the moment:
// Get all tags and display
function tags_filter() {
$tax = 'post_tag';
$terms = get_terms( $tax );
$count = count( $terms );
if ( $count > 0 ): ?>
<div class="post-tags">
<?php
foreach ( $terms as $term ) {
$term_link = get_term_link( $term, $tax );
echo '' . $term->name . ' ';
} ?>
</div>
<?php endif; }
// Script for getting posts
function ajax_filter_get_posts( $taxonomy ) {
// Verify nonce
if( !isset( $_POST['afp_nonce'] ) || !wp_verify_nonce($_POST['afp_nonce'], 'afp_nonce' ) )
die('Permission denied');
$taxonomy = $_POST['taxonomy'];
// WP Query
$args = array(
'tag' => $taxonomy,
'post_type' => 'post',
'posts_per_page' => -1,
'meta_key' => 'datetime',
'orderby' => array(
'datetime' => 'ASC'
),
);
// If taxonomy is not set, remove key from array and get all posts
if( !$taxonomy ) {
unset( $args['tag'] );
}
$query = new WP_Query( $args );
if ( $query->have_posts() ) : while($query->have_posts()) : $query>the_post();
$today = date('Y-m-d H:i:s', strtotime('+9 hours'));
$event_date = get_field('datetime');
if (strtotime($today) <= strtotime($event_date)) {
?>
<div class="sl">
<div class="sl_closed">
<div class="col-2-8"><div class="modulepad">
<p><?php the_field('datetime'); ?></p>
</div></div>
<div class="col-3-8"><div class="modulepad">
<p><?php the_title(); ?><br>
<?php $wpmovieinput = get_field('movie_title'); $movie = imdb_connector_get_movie($wpmovieinput); echo implode(", ", $movie["directors"]); ?>
</p>
</div></div>
<div class="col-3-8"><div class="modulepad">
<p><?php the_field('location_name'); ?><br>
<?php $wpmovieinput = get_field('movie_title'); $movie = imdb_connector_get_movie($wpmovieinput); echo implode(", ", $movie["countries"]) . " "; echo $movie["released"] . " "; echo implode(", ", $movie["runtime"]); ?>
</p>
</div></div>
</div><!--SL_CLOSED-->
<?php } endwhile; ?>
<?php else: ?>
<h2>No posts found</h2>
<?php endif;
die();
}
add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');
what I'm trying to accomplish is to have image thumbnails replace the dropdown box in a woocommerce variation product page. The way I went to trying to get that to work is when a user clicks on an variation product image, the (will be hidden) dropdown box will change to the correct value just as if the user had interacted with the dropdown box itself. the file I'm working with is variable.php.
Here is a snippet of the code. All my custom codes start with the option tag loop just before the closing Select tag.
$loop = 0; foreach ( $attributes as $name => $options ) : $loop++; $countimg = 0;?>
<select id="<?php echo esc_attr( sanitize_title( $name ) ); ?>" name="attribute_<?php echo sanitize_title( $name ); ?>" >
<option value=""><?php echo __( 'Choose an option', 'woocommerce' ) ?>…</option>
<?php
if ( is_array( $options ) ) {
if ( isset( $_REQUEST[ 'attribute_' . sanitize_title( $name ) ] ) ) {
$selected_value = $_REQUEST[ 'attribute_' . sanitize_title( $name ) ];
} elseif ( isset( $selected_attributes[ sanitize_title( $name ) ] ) ) {
$selected_value = $selected_attributes[ sanitize_title( $name ) ];
} else {
$selected_value = '';
}
// Get terms if this is a taxonomy - ordered
if ( taxonomy_exists( $name ) ) {
$orderby = wc_attribute_orderby( $name );
switch ( $orderby ) {
case 'name' :
$args = array( 'orderby' => 'name', 'hide_empty' => false, 'menu_order' => false );
break;
case 'id' :
$args = array( 'orderby' => 'id', 'order' => 'ASC', 'menu_order' => false, 'hide_empty' => false );
break;
case 'menu_order' :
$args = array( 'menu_order' => 'ASC', 'hide_empty' => false );
break;
}
$terms = get_terms( $name, $args );
$count = 1;
foreach ( $terms as $term ) {
if ( ! in_array( $term->slug, $options ) )
continue;
echo '<option id="' . $count . '" value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $term->slug ), false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
$count++;}
} else {
foreach ( $options as $option ) {
echo '<option id="' . $count . '" value="' . esc_attr( sanitize_title( $option ) ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $option ), false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
$count++;}
}
}
?>
</select>
<div>
<?php foreach ( $available_variations as $available_variation ) {
$countimg++;
$image_links = $available_variation['image_link'];
echo '<img id="' . $countimg . '" src="' . $image_links . '" onclick="selectVariationOption(this.id)" style="height:65px; margin-bottom:5px;">';
}?>
</div>
<script>
function selectVariationOption(clicked_id) {
document.getElementById("<?php echo esc_attr( sanitize_title( $name ) ); ?>").selectedIndex = clicked_id;
}
</script>
<?php
if ( sizeof($attributes) == $loop )
echo '<a class="reset_variations" href="#reset">' . __( 'Clear selection', 'woocommerce' ) . '</a>';
?>
<?php endforeach;?>
</div>
</div>
What I did here was I added a numerical ID to the option tags and increases with each additional option available. I then showed the available image variations and added a numerical ID that looped to match the corresponding option ID. Finally, I used a simple javascript that when an image is clicked, the dropdown box changes to the correct selectedIndex. The problem is, the page doesn't react to the changes as if the dropdown box was directly interacted with. In short, nothing happens but the dropdown box changing visual value. I want it so that clicking on the image would be the exact same as clicking on an option in the dropdown box.
Let me know if you need more clarification or information. Thanks in advance!
Using the Variation Swatches and Photos plugin worked. Just had to go in and edit the plugin's variable.php to show all the information that was missing from my original variable.php file. Now I just have to spend a couple hours editing each product.