Need to reload page twice, when calling woocommerce_product_query - php

I've got these 3 functions in my functions.php (sorry for the newbie code).
There's a submit button, and a dropdown. User selects a country in the list of options and press submit. The custom_product_query_tax_query is then run, and sorts the products by the slug Denmark or Europa. It's working, however, I need to press the submit button twice, or atleast reload the page manually for the changes to be visible.
Do I need to call the woocommerce_product_query before other content, or am I simply doing it all wrong?
//Before shop loop we inject the dropdown form with submit button.
//We also preselect the last option choosen, based on the country in session.
function report_button()
{
// display button only on posts
if ( !is_single() )
{
$retrive_data = WC()->session->get( 'Country' );
$denmark = '';
$europe = '';
if($retrive_data === 'Denmark')
{
$denmark = 'selected';
}
else
{
$europe = 'selected';
}
$content .= '<form action="" method="POST">
<select name="select_name[]" id="">
<option value="Europe" '. $europe .'>Vis alle produkter</option>
<option value="Denmark" '. $denmark .'>Vis kun lovlige i Danmark</option>
</select>
<input type="submit">
</form>';
echo $content;
}
}
add_action( 'woocommerce_before_shop_loop', 'report_button', 10 );
//On submit, we set the selected country in a session variable.
add_action( 'template_redirect', 'wpse149613_form_process' );
function wpse149613_form_process()
{
if(isset($_POST['select_name'])){ // select_name will be replaced with your input filed name
$getInput = $_POST['select_name']; // select_name will be replaced with your input filed name
foreach ($getInput as $option => $value) {
$selectedOption = $value;
WC()->session->set( 'Country' , $selectedOption );
}
}
}
//Custom woocommerce product query, show only products with Slug, Denmark.
function custom_product_query_tax_query( $q )
{
if( is_admin() ) return $q;
$retrive_data = WC()->session->get( 'Country' );
if ( $retrive_data == 'Denmark' )
{
$tax_query = (array) $q->get( 'tax_query' );
$tax_query[] = array(
'taxonomy' => 'product_tag',
'field' => 'slug',
'terms' => array( 'Denmark' ),
'operator' => 'IN'
);
$q->set( 'tax_query', $tax_query );
}
else
{
return $q;
}
}
add_filter( 'woocommerce_product_query', 'custom_product_query_tax_query', 10, 2 );

Alright, I seem to have found the answer elsewhere. The template_redirect function hook, needs somewhere to redirect to. I added this to the buttom of the code, and it works!
$current_url = home_url( add_query_arg( array(), $wp->request ) );
wp_redirect($current_url);
exit;

Related

Woocommerce add_filter vs. add_action when asking about specific product meta

I'm struggling with a basic php function.
I implemented a backend checkbox in wordpress / woocommerce general tab which works fine:
// Add checkbox in Backend
function action_woocommerce_product_options_general_product_data() {
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_prevent_add_to_cart_button', // Required, it's the meta_key for storing the value (is checked or not)
'label' => __( 'Warenkorb Button', 'woocommerce' ), // Text in the editor label
'desc_tip' => false, // true or false, show description directly or as tooltip
'description' => __( 'Warenkorb Button ausblenden', 'woocommerce' ) // Provide something useful here
) );
}
add_action( 'woocommerce_product_options_general_product_data', 'action_woocommerce_product_options_general_product_data', 10, 0 );
// Save Field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset, yes or no
$checkbox = isset( $_POST['_prevent_add_to_cart_button'] ) ? 'yes' : 'no';
// Update meta
$product->update_meta_data( '_prevent_add_to_cart_button', $checkbox );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
Now i want to ask for the value of that checkbox and do things based on it.
It works in this function as expected:
// Add function for category / listing page add to cart button hook
function hide_listingpage_button( $add_to_cart_html, $product, $args ){
$hide_add_to_cart_button = $product->get_meta( '_prevent_add_to_cart_button' );
if ( $hide_add_to_cart_button == 'yes' ) {
$before = '<span style="display:none;">';
$after = '</span>';
return $before . $add_to_cart_html . $after;
}
else {
return $add_to_cart_html;
}
}
add_filter( 'woocommerce_loop_add_to_cart_link', 'hide_listingpage_button', 10, 3 );
but it does not work in this function(s):
// Add functions for singlepage before / after add to cart button hook
function beforehide_singlepage_button( $product ) {
$hide_add_to_cart_button = $product->get_meta( '_prevent_add_to_cart_button' );
if ( $hide_add_to_cart_button == 'yes' ) {
echo 'test after';
}
}
function afterhide_singlepage_button( $product ) {
$hide_add_to_cart_button = $product->get_meta( '_prevent_add_to_cart_button' );
if ( $hide_add_to_cart_button == 'yes' ) {
echo 'test after';
}
}
add_action( 'woocommerce_before_add_to_cart_button', 'beforehide_singlepage_button' );
add_action( 'woocommerce_after_add_to_cart_button', 'afterhide_singlepage_button' );
Im my opinion im doing basically the same things?
I give the $product object as argument in the function, ask then for yes / no boolean with
$hide_add_to_cart_button = $product->get_meta( '_prevent_add_to_cart_button' );
and then echo something with the if clause.
however, i get no output of the page from that line, and also no error message.
What am i missing?
thank you!

Add a dropdown Filter for a custom metakey on WooCommerce admin orders

I have the below custom metakey which is an optin checkbox during checkout:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['marketing_opting'] ) )
update_post_meta( $order_id, 'marketing_opting', $_POST['marketing_opting'] );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$marketing_opting = get_post_meta( $order->get_id(), 'marketing_opting', true );
if( $marketing_opting == 1 )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<p align="center">Opted in?</p>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
switch($column){
case 'order_marketing' : echo '<p align="center"><span class="dashicons dashicons-yes"></span><span style="color: #F21891; font-weight: 600;">Signed Up</span></p>';
break;
}
}
So above is working and shows below the column, but I would like to have a filter in the admin bar and a search for Signed Up gives the desired result:
The search is not working, because the value of the checkbox for checked is 1 and does not resognise other words. I have added below, but it's not giving the result:
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = 'marketing_opting';
return $meta_keys;
}
The admin bar filter; the only related posts I could find are all about order statuses and not a custom metakey. I am not sure how to add this correctly, I started with the below, but there are obvious errors, and I am stuck.
add_filter( 'views_edit-shop_order' , 'marketing_opt_in_filter', 10, 1);
function marketing_opt_in_filter( $views ) {
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
$query_string = admin_url( 'edit.php?post_type=shop_order' ) ;
$query_string = add_query_arg( 'marketing_opting' , 'yes' , $query_string ) ;
$views[ 'marketing_opting' ] = 'Opted In (%s)' ;
return $views ;
}
I have revisited your existing code a bit and added a dropdown filter for the "marketing optin" custom field:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field as custom order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_create_order', 'action_checkout_update_order_meta', 10, 2 );
function action_checkout_update_order_meta( $order, $data ) {
if( isset($_POST['marketing_opting']) )
$order->update_meta_data( '_marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Save the optin field as custom user meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer_meta', 10, 2 );
function action_checkout_update_customer_meta( $customer, $data ) {
if( isset($_POST['marketing_opting']) )
$customer->update_meta_data( 'marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $order->get_meta( '_marketing_opting' ) === 'yes' )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<div align="center">' .__("Opted in?") . '</div>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
global $post, $the_order;
if ($column ==='order_marketing') {
$value = $the_order->get_meta( '_marketing_opting' );
$label = $value === 'yes' ? __('Signed Up') : ucfirst($value);
$color = $value === 'yes' ? 'color:#00cc00;' : 'color:#bbbbbb;';
echo '<p align="center" style="'.$color.'"><span class="dashicons dashicons-'.$value.'"></span><span style="font-weight:600;">'.$label.'</span></p>';
}
}
// 3. Make marketing optin meta searchable from search field (can't work very well for 'yes' or 'no' values!)
// Make a custom meta field searchable from the admin order list search field
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = '_marketing_opting';
return $meta_keys;
}
// 4. Add a dropdown filter to get orders by marketing optin meta value
// Add a dropdown to filter orders by Marketing optin
add_action( 'restrict_manage_posts', 'display_admin_shop_order_marketing_opting_filter' );
function display_admin_shop_order_marketing_opting_filter(){
global $pagenow, $post_type;
if( 'shop_order' === $post_type && 'edit.php' === $pagenow ) {
$domain = 'woocommerce';
$current = isset($_GET['filter_shop_order_marketing'])? $_GET['filter_shop_order_marketing'] : '';
echo '<select name="filter_shop_order_marketing">
<option value="">' . __('Filter Marketing optin', $domain) . '</option>';
$options = ['yes' => __('Signed Up'), 'no' => __('No')];
foreach ( $options as $key => $label ) {
printf( '<option value="%s"%s>%s</option>', $key,
$key === $current ? '" selected="selected"' : '', $label );
}
echo '</select>';
}
}
// Process the filter dropdown for orders by Marketing optin
add_filter( 'request', 'process_admin_shop_order_marketing_opting_filter', 99 );
function process_admin_shop_order_marketing_opting_filter( $vars ) {
global $pagenow, $typenow;
if ( $pagenow == 'edit.php' && isset( $_GET['filter_shop_order_marketing'] )
&& $_GET['filter_shop_order_marketing'] != '' && 'shop_order' === $typenow ) {
$vars['meta_key'] = '_marketing_opting';
$vars['meta_value'] = wc_clean( $_GET['filter_shop_order_marketing'] );
}
return $vars;
}
Note: I have change the order meta_key to _marketing_opting starting with an underscore as most other existing metakeys...
Also I have added a function that register that "marketing optin" value in user meta data, as it will be used by checkout on WC()->checkout->get_value( 'marketing_opting' ) for customers that have already made an order.
Field validation (optional)
If you make this checkout field required, you will need field validation… Then add the following:
// Custom Checkout field validation
add_action('woocommerce_checkout_process', 'custom_checkout_field_validation');
function custom_checkout_field_validation() {
if ( isset($_POST['marketing_opting']) ) {
wc_add_notice( '<strong>'. __("Please select a value", "woocommerce") . '</strong> | '.$_POST['marketing_opting'], 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Show custom data in emails, order details woocommerce

Updated:
I'm building a WooCommerce site where the user selects a series of options from dropdowns in the single product page which then display in the cart page and, thanks to help I've received on here, in the checkout as well. The options selected also influence the price of the product. I start with two product variations: 'Print' and 'Original' (the site is selling antique maps).
Everything works fine up till the checkout where all the order details display correctly but, after having placed the order, the details don't appear on the 'order received' screen under 'order details' nor do they appear in the customer confirmation email.
To give some background, the different variations are selected using jQuery, and added to hidden fields a per example below:
$( ":root" ).find("#mapchest-custom-fields").append("<input type='hidden'
name='test' value='wibble'>");
...and these hidden fields are then referenced to add the details to the cart in the following manner:
add_filter('woocommerce_add_cart_item_data','add_custom_field_data', 20,3);
function add_custom_field_data($cart_item_data, $product_id, $variation_id)
{
if(isset($_REQUEST['test']) && ! empty( 'test' )) { // not
$mc_test = sanitize_text_field($_POST['test']);
$cart_item_data['custom_data']['test'] = array(
'label' => 'Test',
'value' => $mc_test
);
}
if(isset($_REQUEST['original_map_vendor_details']) && ! empty(
'original_map_vendor_details' )) {
$mc_original_map_size =
sanitize_text_field($_REQUEST['original_map_vendor_details']);
$cart_item_data['custom_data']['original_map_vendor_details'] =
array(
'label' => 'Vendor',
'value' => $mc_original_map_size
);
}
// process above repeated for other fields
return $cart_item_data;
}
The details are displayed in the cart and checkout using the following function:
add_filter('woocommerce_get_item_data','wdm_add_item_meta',10,2);
function wdm_add_item_meta($cart_data, $cart_item)
{
$custom_items = array();
if( !empty( $cart_data ) )
$custom_items = $cart_data;
if( isset( $cart_item['custom_data'] ) ) {
foreach( $cart_item['custom_data'] as $key => $custom_data ){
if( $key != 'key' ){
$custom_items[] = array(
'name' => $custom_data['label'],
'value' => $custom_data['value'],
);
}
}
}
return $custom_items;
}
What I want to do, as I say is have the details display in the Order Received page and the emails but I can't make it work. I know that for emails I need to hook it to one of the email hooks but I don't know how to access the data sent to the cart in the function above.
I've tried adding using the woocommerce_checkout_create_order_line_item hook to along these lines:
add_action( 'woocommerce_checkout_create_order_line_item',
'add_custom_order_line_item_meta', 20,4 );
function add_custom_order_line_item_meta($item, $cart_item_key, $values,
$order)
{
if( array_key_exists('test', $values['custom_data']) ){
$item->update_meta_data( 'Test', $values['custom_data']['test'] );
}
}
...but whilst I can see the data if I var_dump it in the email like this:
add_action('woocommerce_email_customer_details',
'add_custom_checkout_field_to_emails_notifications', 25, 4 );
function add_custom_checkout_field_to_emails_notifications( $order,
$sent_to_admin, $plain_text, $email ) {
var_dump($order);
}
So, in summary, I have the data working and displaying up to the point of the checkout. After that, I want it to display in customer confirmation emails and on the 'order received' page but I'm having trouble accessing the data. Having looked through other questions on the same subject i would have thought that this would happen automatically regarding the order received page but it doesn't. I suspect there's a stage missing in the code but I can't work out what it should be.
Any tips as to what I'm doing wrong here?
Thanks in advance.
ps. I've now managed to display the fields in the confirmation email (after a fashion) using the following functions:
add_action( 'woocommerce_checkout_create_order_line_item',
'add_custom_order_line_item_meta', 20,4 );
function add_custom_order_line_item_meta($item, $cart_item_key, $values,
$order)
{
if ( isset( $values['custom_data'] ) ) {
$item->update_meta_data( __('The Custom Data', 'woocommerce'),
$values['custom_data'] );
}
}
and
add_action('woocommerce_email_customer_details',
'add_custom_checkout_field_to_emails_notifications', 25, 4 );
function add_custom_checkout_field_to_emails_notifications( $order,
$sent_to_admin, $plain_text, $email ) {
// var_dump($order);
foreach( $order->get_items() as $item_id => $item ){
$custom_data = $item->get_meta( 'The Custom Data' );
foreach( $custom_data as $key => $value ){
foreach( $value as $key1 => $value1 ){
$output = '';
$output .= '<span class="text">' . $value1 . '</span>';
echo $output;
}
echo "<br>";
}
echo "<br><br>";
// var_dump($custom_data );
}
'</strong> <span class="text">' . $order->get_data() . '</span></div>';
}
but this is a hacky solution and doesn't address the underlying problem of why the information isn't appearing in the order received page or directly in the order line items in the email.
Okay, I've worked this out. I'm putting the answer here for the benefit of anyone else having the same problem. Basically, my process was missing a stage. In order to achieve the above you do as follows:
Define the value you wish to pass as meta data. In my own case I used a hidden field but this can equally be set with a text input, a dropdown or other input field. In my case I used jquery to append this to an empty div with id 'mapchest-custom-fields' which I hooked into the process before the cart button. It can equally be set with a static value.
<?php
function define_container_div() {
?>
<div id="mapchest-custom-fields"></div>
<?php
}
add_action( 'woocommerce_before_add_to_cart_button', 'define_container_div', 20 );
?>
...jQuery code to append the value. Value can be dynamic as well:
$( ":root" ).find("#mapchest-custom-fields").append("<input type='hidden' name='test' value='wibble'>");
Next you add the value to your cart item data:
function add_values_to_cart_item_data( $cart_item_data, $product_id, $variation_id )
{
if(isset($_POST['test']) && ! empty( 'test' )) {
$test = filter_input( INPUT_POST, 'test' );
$cart_item_data['test'] = $test;
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_values_to_cart_item_data', 10, 3);
Next, you display the value in your cart:
function display_data_in_cart( $item_data, $cart_item ) {
$item_data[] = array(
'key' => __( 'Test', 'mapchest' ),
'value' => wc_clean( $cart_item['test'] ),
);
return $item_data;
}
add_filter( 'woocommerce_get_item_data', 'display_data_in_cart', 10, 2 );
And finally, you add the data to your order items:
function add_data_to_order_items( $item, $cart_item_key, $values, $order ) {
$item->add_meta_data( __( 'Test', 'mapchest' ), $values['test'] );
}
add_action( 'woocommerce_checkout_create_order_line_item', 'add_data_to_order_items', 10, 4 );
The above process works for me. It displays the custom data in the cart and in the checkout and persists it through to the 'Order Received' page archived orders and the confirmation email (not checked other emails yet).
Thanks to https://iconicwp.com/blog/add-custom-cart-item-data-woocommerce/ for explaining this process to me.

How to validate a custom field on the Variable product on 'add to cart' submit [duplicate]

This question already has an answer here:
Custom field validation in Woocommerce single product pages [closed]
(1 answer)
Closed 4 years ago.
I'm trying to validate the input field of a product variant.
Only this variant has a field for input.
The product works and is added to cart correctly.
My issue is that I want to make sure the input value is numeric because this value will be the product price.
The hook I have found that could support this:
woocommerce_add_to_cart_validation
The issue is it only passed the product id and not the variant id and I also cant see any data the user inputted.
So I need to validate the variable product custom input before the item is added to cart .....
my code for testing this: (just a series of echo's to see inside the vars I'm trying)
function filter_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = '', $variations= array(),$cart_item_data = array(),$item='' ) {
echo'Passed var:<br>';
echo'<pre>';
print_r($passed);
echo'</pre>';
echo'product id var:<br>';
echo'<pre>';
print_r($product_id);
echo'</pre>';
echo'quantity var:<br>';
echo'<pre>';
print_r($quantity);
echo'</pre>';
echo'variation id var:<br>';
echo'<pre>';
print_r($variation_id);
echo'</pre>';
echo'variations var:<br>';
echo'<pre>';
print_r($variations);
echo'</pre>';
echo'Cart Item data var:<br>';
echo'<pre>';
print_r($cart_item_data);
echo'</pre>';
echo' Item data var:<br>';
echo'<pre>';
print_r($item);
echo'</pre>';
die;
};
add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 3 );
The output is as follows:
Passed var:
1
product id var:
1331
quantity var:
1
variation id var:
variations var:
Array
(
)
Cart Item data var:
Array
(
)
Item data var:
This is the function I have to make this field for reference :
add_action('woocommerce_before_add_to_cart_button', 'custom_product_field', 10 );
function custom_product_field() {
global $product;
if ( $product->is_type('variable') ) {
?>
<style>
.my-field-class-custom-product {
display:none;
}
.custominvisible {
display:none;
}
</style>
<script>
jQuery(document).ready(function($) {
var cols = document.getElementsByClassName('woocommerce-variation-price');
function toggleFields() {
if ($('input.variation_id').val() != "1332")
{
$("#product_custom_price_field").hide();
$(cols).css("display", "inherint");
}
else
{
$("#product_custom_price_field").show();
$(cols).css("display", "none");
}
}
$('input.variation_id').change( function(){
if( '' != $('input.variation_id').val() ) {
toggleFields();
}
});
});
</script>
<?php
echo '<br><div>';
woocommerce_form_field('product_custom_price', array(
'type' => 'text',
'class' => array( 'my-field-class-custom-product form-row-wide') ,
'label' => __('Enter the custom amount you wish to buy') ,
'placeholder' => __('') ,
'required' => false,
) , '');
echo '</div>';
}
}
Here I insert the field data into the cart item data :
function add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if( ! empty( $_POST['product_custom_price'] ) ) {
$product = wc_get_product( $variation_id );
$price = $product->get_price();
$cart_item_data['custom_amount'] = $_POST['product_custom_price'];
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_data', 10, 3 );
Then finally here I update the variable product with the new price:
function before_calculate_totals( $cart_obj ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Iterate through each cart item
foreach( $cart_obj->get_cart() as $key=>$value ) {
if( isset( $value['custom_amount'] ) ) {
$price = $value['custom_amount'];
$value['data']->set_price( ( $price ) );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'before_calculate_totals', 10, 1 );
So a work around I have is to instead use jquery and stop the entry on input, I added this script.
<script>
jQuery(document).ready(function($) {
$('#product_custom_price').keyup( function(){
//var aaa = $('#product_custom_price').val()
//console.log(aaa);
if (isNaN($('#product_custom_price').val() / 1) == true) {
alert('Please enter numbers only for the amount');
$('#product_custom_price').val('');
}
});
});
</script>
I'm VERY open to someone showing me a better option !!
If you add this to the validation filter can you get the product variation ID?
<?php
if ($product->product_type == 'variable'):
$children = $product->get_children( $args = '', $output = OBJECT );
foreach ($children as $key=>$value) {
$product_variatons = new WC_Product_Variation($value);
if ( $product_variatons->exists() && $product_variatons-
>variation_is_visible() ) {
$variations[$value] = $product_variatons->get_variation_attributes();
}
}
endif;
Here is the perfect answer .. well for my case anyways..
function my_validate_custom_field( $passed, $product_id, $quantity ) {
$myValitation = $_POST['product_custom_price'];
if( !$myValitation ) {
// Fails validation
$passed = false;
wc_add_notice( __( 'Please enter an amount you wish to buy', 'cfwc' ), 'error' );
}elseif(!is_numeric($myValitation)){
$passed = false;
wc_add_notice( __( 'Please enter numbers only', 'cfwc' ), 'error' );
}elseif($myValitation <1){
$passed = false;
wc_add_notice( __( 'Please enter an amount greater than 1', 'cfwc' ), 'error' );
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'my_validate_custom_field', 10, 3 );

adding a products per page dropdown to woocommerce

I'm trying to add a 'products per page' dropdown to my woocommerce storefront child theme without using a plugin. I'm adding the below code to my functions.php source
add_action( 'woocommerce_before_shop_loop', 'ps_selectbox', 25 );
function ps_selectbox() {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
echo '<div class="woocommerce-perpage">';
echo '<span>Per Page: </span>';
echo '<select onchange="if (this.value) window.location.href=this.value">';
$orderby_options = array(
'8' => '8',
'16' => '16',
'32' => '32',
'64' => '64'
);
foreach( $orderby_options as $value => $label ) {
echo "<option ".selected( $per_page, $value )." value='?perpage=$value'>$label</option>";
}
echo '</select>';
echo '</div>';
}
add_action( 'pre_get_posts', 'ps_pre_get_products_query' );
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if( $query->is_main_query() && !is_admin() && is_post_type_archive( 'product' ) ) {
$query->set( 'posts_per_page', $per_page );
}
}
When I do this, the drop down box shows but any option I choose just takes me back to the front page of my theme.
Can anyone help me?
You can add the below codes into functions.php file. Reference:
The first step is to display a select box on the shop archive page. With some basic php we can echo a select box via the woocommerce_before_shop_loop hook.
add_action( 'woocommerce_before_shop_loop', 'ps_selectbox', 25 );
function ps_selectbox() {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
echo '<div class="woocommerce-perpage">';
echo '<span>Per Page: </span>';
echo '<select onchange="if (this.value) window.location.href=this.value">';
$orderby_options = array(
'8' => '8',
'16' => '16',
'32' => '32',
'64' => '64'
);
foreach( $orderby_options as $value => $label ) {
echo "<option ".selected( $per_page, $value )." value='?perpage=$value'>$label</option>";
}
echo '</select>';
echo '</div>';
}
Some inline jQuery has been added so everytime the select box is changed the “products per page” varibale is sent to the browser.
The filter_input() function gets the external variable which in this case is the number of products to show and sanitizes it.
Now everything is in place we can run the pre_get_posts hook with number of products per page via the “get” method.
add_action( 'pre_get_posts', 'ps_pre_get_products_query' );
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if( $query->is_main_query() && !is_admin() && is_post_type_archive( 'product' ) ){
$query->set( 'posts_per_page', $per_page );
}
}
This is the most simpliest of methods to add a “products per page” dropdown for your WooCommerce store, alternativle you could go about using an ajax method.
I'm using the following code taken from here-
http://designloud.com/how-to-add-products-per-page-dropdown-to-woocommerce/?showmodaldialog=1#comment-1554
// Lets create the function to house our form
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
function woocommerce_catalog_page_ordering() {
?>
<?php echo '<span class="itemsorder">Items Per Page:' ?>
<form action="" method="POST" name="results" class="woocommerce-ordering">
<select name="woocommerce-sort-by-columns" id="woocommerce-sort-by-columns" class="sortby" onchange="this.form.submit()">
<?php
//Get products on page reload
if (isset($_POST['woocommerce-sort-by-columns']) && (($_COOKIE['shop_pageResults'] <> $_POST['woocommerce-sort-by-columns']))) {
$numberOfProductsPerPage = $_POST['woocommerce-sort-by-columns'];
} else {
$numberOfProductsPerPage = $_COOKIE['shop_pageResults'];
}
// This is where you can change the amounts per page that the user will use feel free to change the numbers and text as you want, in my case we had 4 products per row so I chose to have multiples of four for the user to select.
$shopCatalog_orderby = apply_filters('woocommerce_sortby_page', array(
//Add as many of these as you like, -1 shows all products per page
// '' => __('Results per page', 'woocommerce'),
'20' => __('20', 'woocommerce'),
'-1' => __('All', 'woocommerce'),
));
foreach ( $shopCatalog_orderby as $sort_id => $sort_name )
echo '<option value="' . $sort_id . '" ' . selected( $numberOfProductsPerPage, $sort_id, true ) . ' >' . $sort_name . '</option>';
?>
</select>
</form>
<?php echo ' </span>' ?>
<?php
}
// now we set our cookie if we need to
function dl_sort_by_page($count) {
if (isset($_COOKIE['shop_pageResults'])) { // if normal page load with cookie
$count = $_COOKIE['shop_pageResults'];
}
if (isset($_POST['woocommerce-sort-by-columns'])) { //if form submitted
setcookie('shop_pageResults', $_POST['woocommerce-sort-by-columns'], time()+1209600, '/', 'www.your-domain-goes-here.com', false); //this will fail if any part of page has been output- hope this works!
$count = $_POST['woocommerce-sort-by-columns'];
}
// else normal page load and no cookie
return $count;
}
add_filter('loop_shop_per_page','dl_sort_by_page');
add_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_page_ordering', 20 );

Categories