I tried to create a checkbox in the product edit site in woocommerce, which allows me to enable/disable a custom badge banner showed only on specific products. I got it working in the normal edit page, but also want to show the checkbox in the product quickedit panel.
I got it working in the product edit page with the code showing below. This was pretty simple as it was working out of the box.
/* 1. Add new checkbox to product edit page (General tab) */
add_action('woocommerce_product_options_general_product_data', 'bbloomer_add_badge_checkbox_to_products');
function bbloomer_add_badge_checkbox_to_products() {
woocommerce_wp_checkbox(array(
'id' => 'custom_badge',
'class' => '',
'label' => 'Echt SPECHTWERK'
)
);
}
/* 2. Save checkbox via custom field */
add_action('save_post', 'bbloomer_save_badge_checkbox_to_post_meta');
function bbloomer_save_badge_checkbox_to_post_meta($product_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
return;
if (isset($_POST['custom_badge'])) {
update_post_meta($product_id, 'custom_badge', $_POST['custom_badge']);
} else
delete_post_meta($product_id, 'custom_badge');
}
// 3. Display badge # single product page if checkbox checked
add_action('woocommerce_single_product_summary', 'bbloomer_display_badge_if_checkbox', 6);
function bbloomer_display_badge_if_checkbox() {
global $product;
if (get_post_meta($product->get_id(), 'custom_badge', true)) {
?> <div class="echt-spechtwerk-badge">
<img class="advantages-symbols" src="<?php echo get_bloginfo('wpurl') . '/wp-content/uploads/echt-SPECHTWERK-V6.svg' ?>">
</div>
<?php
}
}
Add the follows code for product bulk edit and quick edit with custom field -
function add_custom_field_in_bulk_edit_quick_edit(){
echo '<div class="inline-edit-group">';
woocommerce_wp_checkbox( array(
'id' => 'custom_badge',
'class' => '',
'label' => 'Echt SPECHTWERK'
) );
echo '</div>';
}
add_action( 'woocommerce_product_quick_edit_end', 'add_custom_field_in_bulk_edit_quick_edit', 99 );
add_action( 'woocommerce_product_bulk_edit_end', 'add_custom_field_in_bulk_edit_quick_edit', 99 );
function save_custom_field_in_bulk_edit_quick_edit( $post_id, $post ){
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
if ( 'product' !== $post->post_type ) return $post_id;
if (isset($_REQUEST['custom_badge'])) {
update_post_meta( $post_id, 'custom_badge', $_REQUEST['custom_badge'] );
} else {
delete_post_meta( $post_id, 'custom_badge' );
}
}
add_action( 'woocommerce_product_bulk_and_quick_edit', 'save_custom_field_in_bulk_edit_quick_edit', 99, 2 );
Related
I have a problem with the code below. With that code, we can select specific product and give them a different style in the shop archive. This is working.
However, I guess there is a error in the code.
Once I activated the checkbox for a product, it always appears in the new style even when I uncheck the checkbox. I assume that I made a error with the get_post_meta object.
Can someone help me with that?
Code to display the check box in the general product settings and add the class, based on the value in the check box
// Add checkbox
function action_woocommerce_product_general_options_product_style_listing_data() {
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_special_product_listing_style', // Required, it's the meta_key for storing the value (is checked or not)
'label' => __( 'Special style', 'woocommerce' ), // Text in the editor label
'desc_tip' => false, // true or false, show description directly or as tooltip
'description' => __( 'Promote a product by changing the style of the product card', 'woocommerce' ) // Provide something useful here
) );
}
add_action( 'woocommerce_product_options_general_product_data', 'action_woocommerce_product_general_options_product_style_listing_data', 10, 0 );
// Save Field
function action_woocommerce_product_general_options_product_style_listing_save( $product ) {
// Isset, yes or no
$checkbox = isset( $_POST['_special_product_listing_style'] ) ? 'yes' : 'no';
// Update meta
$product->update_meta_data( '_special_product_listing_style', $checkbox );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_product_general_options_product_style_listing_save', 10, 1 );
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
if ( get_post_meta( $product->get_id(), '_special_product_listing_style', true ) ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
CSS to style the specific products:
/* Custom special product listing style */
li.sales-flash-overlay.woocommerce-text-align-left.woocommerce-image-align-center.do-quantity-buttons.product.type-product.post-10800.status-publish.first.instock.product_cat-crafty-beer-club.has-post-thumbnail.featured.sold-individually.taxable.shipping-taxable.product-type-variable.custom-product-listing-class {
border: 2px solid;
border-style: dashed;
}
Replace
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
if ( get_post_meta( $product->get_id(), '_special_product_listing_style', true ) ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
With
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
// Get meta
$spls = $product->get_meta( '_special_product_listing_style' );
// Compare
if ( $spls == 'yes' ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
That should suffice for your code to function fully
The following code add a custom field to admin product settings to manage guest checkout at product level:
// Display Guest Checkout Field
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
function woo_add_custom_general_fields() {
global $woocommerce, $post;
echo '<div class="options_group">';
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_allow_guest_checkout',
'wrapper_class' => 'show_if_simple',
'label' => __('Checkout', 'woocommerce' ),
'description' => __('Allow Guest Checkout', 'woocommerce' )
) );
echo '</div>';
}
// Save Guest Checkout Field
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
$woocommerce_checkbox = isset( $_POST['_allow_guest_checkout'] ) ? 'yes' : 'no';
update_post_meta( $post_id, '_allow_guest_checkout', $woocommerce_checkbox );
}
// Enable Guest Checkout on Certain products
add_filter( 'pre_option_woocommerce_enable_guest_checkout', 'enable_guest_checkout_based_on_product' );
function enable_guest_checkout_based_on_product( $value ) {
if ( WC()->cart ) {
$cart = WC()->cart->get_cart();
foreach ( $cart as $item ) {
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) == 'yes' ) {
$value = "yes";
} else {
$value = "no";
break;
}
}
}
return $value;
}
But it doesn't work actually. What I am doing wrong? How can I fix it?
I am trying to allow guest purchases for specific products. The admin custom field display and save custom field value is working (the 2 first functions), But login/register never comes up on checkout page, even if there are products in cart that doesn't allow guest checkout.
The filter hook enable_guest_checkout_based_on_product doesn't exist anymore and has been replaced by another hook a bit different.
So your code is going to be:
add_filter( 'woocommerce_checkout_registration_required', 'change_tax_class_user_role', 900 );
function change_tax_class_user_role( $registration_required ) {
if ( ! WC()->cart->is_empty() ) {
$registration_required = false; // Initializing (allowing guest checkout by default)
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Check if there is any item in cart that has not the option "Guest checkout allowed"
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) !== 'yes' ) {
return true; // Found: Force checkout user registration and exit
}
}
}
return $registration_required;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Related continuation: Redirection for non checkout guest allowed in WooCommerce
I've been looking for a solution to this for a while now... I am trying to show or hide specific shipping rates based on a radio button option added to the Woocommerce checkout page. But I don't know anything about Ajax & JQuery which I believe it requires.
Basically if a user selects radio option_1 it will ONLY show 'flat_rate:1' & 'flat_rate:2'. If the user selects radio option_2 it will ONLY show 'flat_rate:3' & 'flat_rate:4'
Click here for example of checkout screen
Here is the code for my radio buttons displayed on checkout page:
add_action( 'woocommerce_review_order_before_payment','tc_checkout_radio_choice' );
function tc_checkout_radio_choice() {
$businesstype = array(
'type' => 'radio',
'class' => array( 'business_residential' ),
'required' => true,
'options' => array(
'option_1' => 'Business',
'option_2' => 'Residential',
),
);
echo '<div id="checkout-radio">';
echo '<h3>Select Your Business Type</h3>';
woocommerce_form_field( 'radio_choice', $businesstype );
echo '</div>';
}
The closest example I've seen comes from an answer provided by 'LoicTheAztec' in this post here: Show/hide shipping methods based on a WooCommerce checkout field value
I'm completely lost with this and the more I try to solve it, the more I get confused.
Here is the correct way to show hide shipping methods based on multiple radio buttons choice on checkout page, that requires to use PHP, Ajax, jQuery and WC Session.
When "Business" radio button is selected (default choice), flat_rate:3 and flat_rate:4 shipping methods will be hidden, so customer will only be able to choose flat_rate:1 or flat_rate:2 shipping methods.
If "Residential" radio button is selected then flat_rate:1 and flat_rate:2 shipping methods will be hidden, so customer will only be able to choose flat_rate:3 or flat_rate:4 shipping methods.
The code:
// Display a Custom radio buttons fields for shipping options
add_action( 'woocommerce_review_order_before_payment','checkout_customer_type_radio_buttons' );
function checkout_customer_type_radio_buttons() {
$field_id = 'customer_type';
echo '<div id="customer-type-radio">';
echo '<h3>' . __("Select Your Business Type", "woocommerce") . '</h3>';
// Get the selected radio button value (if selected)
$field_value = WC()->session->get( $field_id );
// Get customer selected value on last past order
if( empty($field_value) )
$field_value = WC()->checkout->get_value( $field_id );
// The default value fallback
if( empty($field_value) )
$field_value = 'Business';
woocommerce_form_field( $field_id, array(
'type' => 'radio',
'class' => array( $field_id ),
'required' => true,
'options' => array(
'Business' => __('Business', 'woocommerce'),
'Residential' => __('Residential', 'woocommerce'),
),
), $field_value );
echo '</div>';
}
// Conditionally show/hide shipping methods
add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
function shipping_package_rates_filter_callback( $rates, $package ) {
$customer_type = WC()->session->get( 'customer_type' ); // Get the customere type
if ( $customer_type === 'Business' ) {
if( isset( $rates['flat_rate:3'] ) )
unset( $rates['flat_rate:3'] );
if( isset( $rates['flat_rate:4'] ) )
unset( $rates['flat_rate:4'] );
}
elseif ( $customer_type === 'Residential' ) {
if( isset( $rates['flat_rate:1'] ) )
unset( $rates['flat_rate:1'] );
if( isset( $rates['flat_rate:2'] ) )
unset( $rates['flat_rate:2'] );
}
return $rates;
}
// function that gets the Ajax data
add_action( 'wp_ajax_get_customer_type', 'wc_get_customer_type' );
add_action( 'wp_ajax_nopriv_get_customer_type', 'wc_get_customer_type' );
function wc_get_customer_type() {
$field_id = 'customer_type';
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ){
WC()->session->set($field_id, $_POST[$field_id] );
}
echo json_encode( WC()->session->get( $field_id ) );
die(); // (required)
}
// The Jquery Ajax script
add_action( 'wp_footer', 'custom_checkout_ajax_jquery_script' );
function custom_checkout_ajax_jquery_script() {
$field_id = 'customer_type';
if( WC()->session->__isset($field_id) )
WC()->session->__unset($field_id);
// Only on checkout when billing company is not defined
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
var fieldId = 'p#customer_type_field input';
function userTypeTriggerAjax( customerType ){
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'get_customer_type',
'customer_type': customerType,
},
success: function (result) {
// Trigger refresh checkout
$('body').trigger('update_checkout');
console.log(result);
}
});
}
// On start
if( $(fieldId).val() != '' ) {
userTypeTriggerAjax( $(fieldId).val() );
}
// On change
$(fieldId).change( function () {
userTypeTriggerAjax( $(this).val() );
});
});
</script>
<?php
endif;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( in_array( WC()->session->get('customer_type' ), ['Business', 'Residential'] ) )
$bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Code based on this related threads:
Remove shipping cost if custom checkbox is checked in WooCommerce Checkout
Show/hide shipping methods based on a WooCommerce checkout field value
If anyone wants to know how to make this a required option with an error notification before payment, this is what I did...
To de-select the radio buttons I removed the value from:
//if( empty($field_value) )
$field_value = '';
And added this code to the checkout process at the end of the code from Loic, which adds a notification message if a radio button has not been selected:
// Show notice if customer does not select a business type
add_action( 'woocommerce_checkout_process', 'business_type_error_message' );
function business_type_error_message() {
if ( ! (int) isset( $_POST['customer_type'] ) ) {
wc_add_notice( __( 'Please select an order type to calculate the correct shipping and proceed with your order.' ), 'error' );
}
}
Hope this helps others out there!
I've been googling and searching here for a simple way to add an empty field box to the Edit Orders page. We will use this to put in a reference for the shipment from our courier.
We would add it to the order notes, but we want it to be searchable, and also want to add it as a column in the Orders Admin page (I have Admin Columns plugin that I think can do that bit, I just need to add this field to start).
Hope someone can help, thanks!
EDIT:
I found this question which seems to be similar, but more complicated, than what I am looking for and I cant figure out how to simplify it. Add a custom meta box on order edit pages and display it on the customer order pages
I don't need anything that will display on the front end to customers like this. Just a simple empty box that displays on every order-edit page (perhaps below the order notes) that can be searched. I will then display it in a column on the order admin page too.
Managed to get an answer, this is working great!
//from::https://codex.wordpress.org/Plugin_API/Action_Reference/manage_posts_custom_column
// For displaying in columns.
add_filter( 'manage_edit-shop_order_columns', 'set_custom_edit_shop_order_columns' );
function set_custom_edit_shop_order_columns($columns) {
$columns['custom_column'] = __( 'Custom Column', 'your_text_domain' );
return $columns;
}
// Add the data to the custom columns for the order post type:
add_action( 'manage_shop_order_posts_custom_column' , 'custom_shop_order_column', 10, 2 );
function custom_shop_order_column( $column, $post_id ) {
switch ( $column ) {
case 'custom_column' :
echo esc_html( get_post_meta( $post_id, 'custom_column', true ) );
break;
}
}
// For display and saving in order details page.
add_action( 'add_meta_boxes', 'add_shop_order_meta_box' );
function add_shop_order_meta_box() {
add_meta_box(
'custom_column',
__( 'Custom Column', 'your_text_domain' ),
'shop_order_display_callback',
'shop_order'
);
}
// For displaying.
function shop_order_display_callback( $post ) {
$value = get_post_meta( $post->ID, 'custom_column', true );
echo '<textarea style="width:100%" id="custom_column" name="custom_column">' . esc_attr( $value ) . '</textarea>';
}
// For saving.
function save_shop_order_meta_box_data( $post_id ) {
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Check the user's permissions.
if ( isset( $_POST['post_type'] ) && 'shop_order' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_shop_order', $post_id ) ) {
return;
}
}
// Make sure that it is set.
if ( ! isset( $_POST['custom_column'] ) ) {
return;
}
// Sanitize user input.
$my_data = sanitize_text_field( $_POST['custom_column'] );
// Update the meta field in the database.
update_post_meta( $post_id, 'custom_column', $my_data );
}
add_action( 'save_post', 'save_shop_order_meta_box_data' );
Use the default WooCommerce custom field in the order edit page bottom section.
I have created form for enquiry. When user fill this form then I am saving it into database as a custom post type. In backend I need to show extra information on custom post edit page. But did not find any hook.
I have tried this code:
[![function add_extra_info_column( $columns ) {
return array_merge( $columns,
array( 'sticky' => __( 'Extra Info', 'your_text_domain' ) ) );
}
add_filter( 'manage_posts_columns' , 'add_extra_info_column' );][1]][1]
But it adds a new column in custom post.
I need to show extra info when we click on edit page link for every post.
This is just an example and you have to customize it for your needs:
First step: Adding Meta container hook to backend (for example here for products post type):
add_action( 'add_meta_boxes', 'extra_info_add_meta_boxes' );
if ( ! function_exists( 'extra_info_add_meta_boxes' ) )
{
function extra_info_add_meta_boxes()
{
global $post;
add_meta_box( 'extra_info_data', __('Extra Info','your_text_domain'), 'extra_info_data_content', 'product', 'side', 'core' );
}
}
(replace 'product' by your post type and this meta box could be like here on 'side' or by 'normal' to get it on main column)
Second step: Adding information in this metabox (fields, data, whatever…)
function extra_info_data_content()
{
global $post;
// Here you show your data <=====
}
References:
function add_meta_box()
How to add custom fields for WooCommerce order page (admin)?
How to add option to woo commerce edit order page?
Third step (optional): Save the data of the custom meta post (needed if you have some fields).
add_action( 'save_post', 'extra_info_save_woocommerce_other_fields', 10, 1 );
if ( ! function_exists( 'extra_info_save_woocommerce_other_fields' ) )
{
function extra_info_save_woocommerce_other_fields( $post_id )
{
// Check if our nonce is set.
if ( ! isset( $_POST[ 'extra_info_other_meta_field_nonce' ] ) )
{
return $post_id;
}
$nonce = $_REQUEST[ 'extra_info__other_meta_field_nonce' ];
//Verify that the nonce is valid.
if ( ! wp_verify_nonce( $nonce ) )
{
return $post_id;
}
// If this is an autosave, our form has not been submitted, so we don't want to do anything.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
{
return $post_id;
}
// Check the user's permissions.
if ( 'page' == $_POST[ 'post_type' ] )
{
if ( ! current_user_can( 'edit_page', $post_id ) )
{
return $post_id;
}
}
else
{
if ( ! current_user_can( 'edit_post', $post_id ) )
{
return $post_id;
}
}
/* --- !!! OK, its safe for us to save the data now. !!! --- */
// Sanitize user input and Update the meta field in the database.
}
}