Validate the add to cart button in Wordpress - wordpress

I am new here and looking for some help. I have used the below code in order to change the add to cart button with quantity. The dropdown starts from 0 to 20. So I would like to add a validation to the button when someone clicks on add button with a 0 qty selected. So can you please help me in validating the 0?
Code used for the dropdown:
function woocommerce_quantity_input() {
global $product;
$defaults = array(
'input_name' => 'quantity',
'input_value' => '1',
'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:5px;', $product )
);
if ( ! empty( $defaults['min_value'] ) )
$min = $defaults['min_value'];
else $min = 0;
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 ) {
$options .= '<option value="' . $count . '">' . $count . '</option>';
}
echo '<div class="quantity_select" style="' . $defaults['style'] . '"><select name="' . esc_attr( $defaults['input_name'] ) . '" title="' . _x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) . '" class="qty">' . $options . '</select></div>';
}

Here is the documentation you can check the how wordpress sanitization work
https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/
https://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data
https://developer.wordpress.org/plugins/security/securing-input/

Related

Quantity field input on related products (woocommerce) doesn't appear

I'm using this hook to show a quantity input on all my woocommerce_loop_add_to_cart_link, but in the related products widget, is the only place that the woocommerce_quantity_input() (input element) doesn't even appear.
Do you know why?
add_filter( 'woocommerce_loop_add_to_cart_link', function( $html, $product ) {
if ( $product && $product->is_type( 'simple' ) && $product->is_purchasable() && $product->is_in_stock() && ! $product->is_sold_individually() ) {
$html = '<form action="' . esc_url( $product->add_to_cart_url() ) . '" class="wcb2b-quantity" method="post" enctype="multipart/form-data" >';
$html .= woocommerce_quantity_input( array(), $product, false );
$html .= '<button type="submit" class="button alt">' . esc_html( $product->add_to_cart_text() ) . '</button>';
$html .= '</form>';
}
return $html;
the woocommerce_quantity_input() is defined here
function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
if ( is_null( $product ) ) {
$product = $GLOBALS['product'];
}
$defaults = array(
'input_id' => uniqid( 'quantity_' ),
'input_name' => 'quantity',
'input_value' => '1',
'classes' => apply_filters( 'woocommerce_quantity_input_classes', array( 'input-text', 'qty', 'text' ), $product ),
'max_value' => apply_filters( 'woocommerce_quantity_input_max', -1, $product ),
'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $product ),
'step' => apply_filters( 'woocommerce_quantity_input_step', 1, $product ),
'pattern' => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
'inputmode' => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
'product_name' => $product ? $product->get_title() : '',
'placeholder' => apply_filters( 'woocommerce_quantity_input_placeholder', '', $product ),
// When autocomplete is enabled in firefox, it will overwrite actual value with what user entered last. So we default to off.
// See #link https://github.com/woocommerce/woocommerce/issues/30733.
'autocomplete' => apply_filters( 'woocommerce_quantity_input_autocomplete', 'off', $product ),
);
$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
// Apply sanity to min/max args - min cannot be lower than 0.
$args['min_value'] = max( $args['min_value'], 0 );
$args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : '';
// Max cannot be lower than min if defined.
if ( '' !== $args['max_value'] && $args['max_value'] < $args['min_value'] ) {
$args['max_value'] = $args['min_value'];
}
ob_start();
wc_get_template( 'global/quantity-input.php', $args );
if ( $echo ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo ob_get_clean();
} else {
return ob_get_clean();
}
}
Related product screenshot: https://ibb.co/vw6Rt4d
Other loops screenshot: https://ibb.co/pRcpBRp

How to add 2 select fields (combobox) to woocommerce checkout page?

I am developing an online store that offers local delivery days according to zip code. I have limited the zip codes with a selection using this snippet
add_filter ('woocommerce_default_address_fields', 'custom_override_default_postcode_field');
function custom_override_default_postcode_field ($address_fields) {
// Zip codes
$postcode_array = array (
'28001' => '28001',
'28002' => '28002',
'28923' => '28923'
);
$address_fields['postcode']['type'] = 'select';
$address_fields['postcode']['options'] = $postcode_array;
return $address_fields;
}
I am using the plugin woocommerce checkout field editor and I've added field "delivery days", which is a select field with the values ​​Monday, Tuesday, Wednesday ...
Now, I want to make the second field dependent on the first, according to my client's specifications, for example:
Zip code 28001 / Delivery Days Monday and Wednesday
Zip code 28002 / Delivery days Tuesday and Thursday
Zip code 28923 / Delivery Days Friday and Sunday
That is, when the buyer chooses a postal code, it only shows him to choose the corresponding days.
If there is a way to do that without the plugin I think it will be better
Thanks a lot for your help,
Luis
This required a lots of customization. Try the below code. code goes to your active theme functions.php file.
add_filter ('woocommerce_default_address_fields', 'custom_override_default_postcode_field');
function custom_override_default_postcode_field ($address_fields) {
// Zip codes
$postcode_array = array (
'28001' => '28001',
'28002' => '28002',
'28923' => '28923'
);
$address_fields['postcode']['type'] = 'select';
$address_fields['postcode']['options'] = $postcode_array;
return $address_fields;
}
You can add a new dropdown field Delivery days using the woocommerce_checkout_fields filter hook.
add_filter( 'woocommerce_checkout_fields' , 'custom_delivery_days_woocommerce_billing_fields' );
function custom_delivery_days_woocommerce_billing_fields( $fields ) {
$fields['billing']['delivery_days'] = array(
'label' => __('Delivery days', 'woocommerce'),
'placeholder' => _x('dropdown', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true,
'priority' => 95,
'type' => 'custom_select',
'options' => array(
'monday' => array(
'label' => __('Monday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28001',
),
'tuesday' => array(
'label' => __('Tuesday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28002',
),
'wednesday' => array(
'label' => __('Wednesday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28001',
),
'thursday' => array(
'label' => __('Thursday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28002',
),
'friday' => array(
'label' => __('Friday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28923',
),
'sunday' => array(
'label' => __('Sunday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28923',
)
)
);
return $fields;
}
Now as per your requirement I will use data attr for show hide select option based on another select option. but in woocommerce default select dropdown, there is now a way to add data attr to select. so for this, I created the custom_select type so we can add data attr. so as you can see in above woocommerce_checkout_fields filter hook i set 'type' => 'custom_select',.
You can add new your custom field type using the woocommerce_form_field filter hook.
add_filter( 'woocommerce_form_field', 'add_custom_select', 10 , 4 );
function add_custom_select( $field, $key, $args, $value ){
if( $args['type'] == 'custom_select' ){
if ( $args['required'] ) {
$args['class'][] = 'validate-required';
$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>';
} else {
$required = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
}
$field = '';
$options = '';
if ( ! empty( $args['options'] ) ) {
foreach ( $args['options'] as $option_key => $option_text ) {
if ( '' === $option_key ) {
// If we have a blank option, select2 needs a placeholder.
if ( empty( $args['placeholder'] ) ) {
$args['placeholder'] = $option_text['label'] ? $option_text['label'] : __( 'Choose an option', 'woocommerce' );
}
$custom_attributes[] = 'data-allow_clear="true"';
}
$options .= '<option value="' . esc_attr( $option_key ) . '" ' . selected( $value, $option_key, false ) . ' data-'.$option_text['data_attr_name'].'="'.$option_text['data_attr_value'].'" >' . esc_html( $option_text['label'] ) . '</option>';
}
$field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' data-placeholder="' . esc_attr( $args['placeholder'] ) . '">
' . $options . '
</select>';
}
$field_container = '<p class="form-row %1$s" id="%2$s" data-priority="' . esc_attr( $sort ) . '">%3$s</p>';
if ( ! empty( $field ) ) {
$field_html = '';
if ( $args['label'] && 'checkbox' !== $args['type'] ) {
$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . wp_kses_post( $args['label'] ) . $required . '</label>';
}
$field_html .= '<span class="woocommerce-input-wrapper">' . $field;
if ( $args['description'] ) {
$field_html .= '<span class="description" id="' . esc_attr( $args['id'] ) . '-description" aria-hidden="true">' . wp_kses_post( $args['description'] ) . '</span>';
}
$field_html .= '</span>';
$container_class = esc_attr( implode( ' ', $args['class'] ) );
$container_id = esc_attr( $args['id'] ) . '_field';
$field = sprintf( $field_container, $container_class, $container_id, $field_html );
}
return $field;
}
return $field;
}
Now on the billing_postcode change, you have to get the billing_postcode value that you need to compare with delivery_days dropdown option data-post-code and based on that you can show hide.
function add_custom_js(){
?>
<script type="text/javascript">
(function($){
$('#billing_postcode').on('change', function(){
var postcode = $(this).val();
var days = $('#delivery_days');
var i = 1;
$('option', days).filter(function(){
if ( $(this).attr('data-post-code') === postcode ) {
$(this).show();
if( i == 1 ){
$("#delivery_days").val($(this).val());
}
i++;
} else {
$(this).hide();
}
});
});
$('#billing_postcode').trigger('change');
})(jQuery);
</script>
<?php
}
add_action( 'wp_footer', 'add_custom_js', 10, 1 );
Tested and works.

wordpress change custom post type title in posts list

I searched a lot how to customize custom posts list,
I managed to add a new columns with manage_commercial_cpi_posts_columns,
But, I need to remove the "title" from the list, and still have the edit, delete options.
How can I do it?
You could hide the title link with CSS or JS, but here's a PHP approach. First remove the title column, and add a custom one:
add_filter( 'manage_commercial_cpi_posts_columns', 'manage_commercial_cpi_posts_columns', 25, 1 );
function manage_commercial_cpi_posts_columns( $cols )
{
// remove title column
unset( $cols['title'] );
// add custom column
$cols['ccpi_links'] = __( 'Edit', 'textdomain' );
// return columns
return $cols;
}
Then, use the row_actions method of the WP_List_Table class to generate the links. Code is copied from the WP_Posts_List_Table class. An important detail is the addition of true as the second parameter of the row_actions method, ensuring the links are always visible.
add_action( 'manage_commercial_cpi_posts_custom_column', 'manage_commercial_cpi_custom_column', 10, 2 );
function manage_commercial_cpi_custom_column( $col, $post_id )
{
switch( $col ) :
case 'ccpi_links' :
// variables
$post = get_post( $post_id );
$title = _draft_or_post_title();
$post_type_object = get_post_type_object( $post->post_type );
$can_edit_post = current_user_can( 'edit_post', $post->ID );
// set up row actions
$actions = array();
if ( $can_edit_post && 'trash' != $post->post_status ) {
$actions['edit'] = '' . __( 'Edit' ) . '';
$actions['inline hide-if-no-js'] = '' . __( 'Quick Edit' ) . '';
}
if ( current_user_can( 'delete_post', $post->ID ) ) {
if ( 'trash' == $post->post_status )
$actions['untrash'] = "<a title='" . esc_attr( __( 'Restore this item from the Trash' ) ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
elseif ( EMPTY_TRASH_DAYS )
$actions['trash'] = "<a class='submitdelete' title='" . esc_attr( __( 'Move this item to the Trash' ) ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
$actions['delete'] = "<a class='submitdelete' title='" . esc_attr( __( 'Delete this item permanently' ) ) . "' href='" . get_delete_post_link( $post->ID, '', true ) . "'>" . __( 'Delete Permanently' ) . "</a>";
}
if ( $post_type_object->public ) {
if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
if ( $can_edit_post ) {
$preview_link = set_url_scheme( get_permalink( $post->ID ) );
/** This filter is documented in wp-admin/includes/meta-boxes.php */
$preview_link = apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $preview_link ), $post );
$actions['view'] = '' . __( 'Preview' ) . '';
}
} elseif ( 'trash' != $post->post_status ) {
$actions['view'] = '' . __( 'View' ) . '';
}
}
// invoke row actions
$table = new WP_Posts_List_Table;
echo $table->row_actions( $actions, true );
break;
endswitch;
}
result

Customize WooCommerce Quantity Selector

I'm trying to change the default +/- quantity selector into a drop down menu with a given amount of number options (i.e. 1-10).
Anyone know how to accomplish this?
Let me know if you'd like me to post any of the code related to this.
I'd like to do this too. So far I found that the quantity markup is generated in woocommerce/templates/single-product/add-to-cart/quantity.php. You could make a copy of this file in a minimal mirror of the woocommerce/templates directory structure in your theme folder, e.g. in this case copy it to yourtheme/woocommerce/single-product/add-to-cart. There you can edit it without altering the plug-in and risk it being overwritten when the plug-in is updated.
There is a plugin that will do this for you called WooCommerce Advanced Product Quantities, it's free and will allow you to set Minimum, Maximum and Step values for all product quantity inputs. Set rules on a per product, per category/tag or site wide.
http://wordpress.org/plugins/woocommerce-incremental-product-quantities/
It also works with WooCommerce Thumbnail Input Quantities which will put those quantity boxes in all of your product thumbnail boxes.
http://wordpress.org/plugins/woocommerce-thumbnail-input-quantities/
Enjoy! Full disclosure, I'm the plugin author.
I have not tried this, but I found this code http://bastutor.blogspot.ca/2014/01/woocommerce-change-input-quantity-to-dropdown.html
/* Change Product Quantity Input to Dropdown */
function woocommerce_quantity_input() {
global $product;
$defaults = array(
'input_name' => 'quantity',
'input_value' => '1',
'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){
$options .= '<option value="' . $count . '">' . $count . '</option>';
}
echo '<div class="quantity_select" style="' . $defaults['style'] . '"><select name="' . esc_attr( $defaults['input_name'] ) . '" title="' . _x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) . '" class="qty">' . $options . '</select></div>';
}
You need to override the template "quantity-input.php" to do so add a file with the name as "quantity-input.php" in your-theme/woocommerce/global/ folder then you can make the changes in that file, now wordpress will use your file to display quantity input html.
Paste this in your function.php file
The dropdown list works both on the product page and in the shopping cart.
Image
function woocommerce_quantity_input($args = array(), $product = null, $echo = true) {
if (is_null($product)) {
$product = $GLOBALS['product'];
}
// Default values
$defaults = array(
'input_name' => 'quantity',
'input_value' => '1',
'max_value' => apply_filters('woocommerce_quantity_input_max', -1, $product),
'min_value' => apply_filters('woocommerce_quantity_input_min', 0, $product),
'step' => 1,
);
$args = apply_filters('woocommerce_quantity_input_args', wp_parse_args($args, $defaults), $product);
$args['min_value'] = max($args['min_value'], 0);
$args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : 10;
if (
'' !== $args['max_value'] && $args['max_value'] < $args['min_value']
) {
$args['max_value'] = $args['min_value'];
}
$options = '';
// Add loop
for ($count = $args['min_value']; $count <= $args['max_value']; $count = $count + $args['step']) {
// Cart item quantity defined?
if ('' !== $args['input_value'] && $args['input_value'] >= 1 && $count == $args['input_value']) {
$selected = 'selected';
} else {
$selected = '';
}
$options .= '<option value="' . $count . '"' . $selected . '>' . $count . '</option>';
}
$html = '<div><div class="quantity form-select-wrapper"><select class="form- select" name="' . $args['input_name'] . '">' . $options . '</select></div><!--/.form-select-wrapper --></div>';
if ($echo) {
echo $html;
} else {
return $html;
}
}
Hi paste this in your function.php file
function woocommerce_quantity_input($data = null) {
global $product;
if (!$data) {
$defaults = array(
'input_name' => 'quantity',
'input_value' => '1',
'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;', $product )
);
} else {
$defaults = array(
'input_name' => $data['input_name'],
'input_value' => $data['input_value'],
'step' => apply_filters( 'cw_woocommerce_quantity_input_step', '1', $product ),
'max_value' => apply_filters( 'cw_woocommerce_quantity_input_max', '', $product ),
'min_value' => apply_filters( 'cw_woocommerce_quantity_input_min', '', $product ),
'style' => apply_filters( 'cw_woocommerce_quantity_style', 'float:left;', $product )
);
}
if ( ! empty( $defaults['min_value'] ) )
$min = $defaults['min_value'];
else $min = 1;
if ( ! empty( $defaults['max_value'] ) )
$max = $defaults['max_value'];
else $max = 15;
if ( ! empty( $defaults['step'] ) )
$step = $defaults['step'];
else $step = 1;
$options = '';
for ( $count = $min; $count <= $max; $count = $count+$step ) {
$selected = $count === $defaults['input_value'] ? ' selected' : '';
$options .= '<option value="' . $count . '"'.$selected.'>' . $count . '</option>';
}
echo '<div class="cw_quantity_select" style="' . $defaults['style'] . '"><select name="' . esc_attr( $defaults['input_name'] ) . '" title="' . _x( 'Qty', 'Product Description', 'woocommerce' ) . '" class="cw_qty">' . $options . '</select></div>';
}

Wordpress bulk trash action using table inherited from WP Posts List Table

In a plugin which shows a table of posts of a custom type, I wanted to add the option for bulk actions. Besides the checkboxes I displayed the control for bulk actions, but when I click Apply, nothing happens.
It's supposed to be an action, I guess, but I couldn't find which one. I tried trash_post, but it doesn't get hit.
How do I perform a bulk delete anyway, since I've no idea if I'm even on the right track.
You will have to define your bulk actions array in your class that extends WP_List_Table then in your display function you will need to define the individual actions.
function get_bulk_actions() {
$actions = array();
if ( $this->is_trash )
$actions['untrash'] = __( 'Restore' );
else
$actions['edit'] = __( 'Edit' );
if ( $this->is_trash || !EMPTY_TRASH_DAYS )
$actions['delete'] = __( 'Delete Permanently' );
else
$actions['trash'] = __( 'Move to Trash' );
return $actions;
}
You can use wp_posts_list_table as an example of how it's done:
$actions = array();
if ( $can_edit_post && 'trash' != $post->post_status ) {
$actions['edit'] = '' . __( 'Edit' ) . '';
$actions['inline hide-if-no-js'] = '' . __( 'Quick Edit' ) . '';
}
if ( current_user_can( $post_type_object->cap->delete_post, $post->ID ) ) {
if ( 'trash' == $post->post_status )
$actions['untrash'] = "<a title='" . esc_attr( __( 'Restore this item from the Trash' ) ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-' . $post->post_type . '_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
elseif ( EMPTY_TRASH_DAYS )
$actions['trash'] = "<a class='submitdelete' title='" . esc_attr( __( 'Move this item to the Trash' ) ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
$actions['delete'] = "<a class='submitdelete' title='" . esc_attr( __( 'Delete this item permanently' ) ) . "' href='" . get_delete_post_link( $post->ID, '', true ) . "'>" . __( 'Delete Permanently' ) . "</a>";
}
if ( $post_type_object->public ) {
if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
if ( $can_edit_post )
$actions['view'] = '' . __( 'Preview' ) . '';
} elseif ( 'trash' != $post->post_status ) {
$actions['view'] = '' . __( 'View' ) . '';
}
}
$actions = apply_filters( is_post_type_hierarchical( $post->post_type ) ? 'page_row_actions' : 'post_row_actions', $actions, $post );
echo $this->row_actions( $actions );
get_inline_data( $post );
echo '</td>';
break;
You also have to add the javascript to make the ajax requests and fill in the data from the hidden inline_ div. Take a look or reuse the code from inline-edit-post-dev.js.

Resources