How can I go about displaying the product 'tax status' (ie. taxable, delivery only, none) on the product list of the admin page?
I've been trying to display products as 'In Stock/Out of Stock' and 'Taxable/Not Taxable' on the product list so that I can easily determine the status of products and make changes if necessary.
I figured out how to display the Stock Status on the product list, however, when I try the same with the 'tax status', it doesn't work. I got Stock Status to display by adding the following code to functions.php. How can I have the 'Tax Status' display?
add_filter( 'manage_edit-product_columns', 'product_column_arrange' );
function product_column_arrange( $product_columns ) {
return array(
...
'is_in_stock' => 'Stock',
...
);
}
The following will display a custom column for product tax status in admin product list:
add_filter( 'manage_edit-product_columns', 'tax_status_product_column');
function tax_status_product_column($columns){
$new_columns = [];
foreach( $columns as $key => $column ){
$new_columns[$key] = $columns[$key];
if( $key == 'is_in_stock' ) {
$new_columns['tax_status'] = __( 'Tax status','woocommerce');
}
}
return $new_columns;
}
add_action( 'manage_product_posts_custom_column', 'tax_status_product_column_content', 10, 2 );
function tax_status_product_column_content( $column, $post_id ){
if( $column == 'tax_status' ){
global $post, $product;
// Excluding variable and grouped products
if( is_a( $product, 'WC_Product' ) ) {
$args = array(
'taxable' => __( 'Taxable', 'woocommerce' ),
'shipping' => __( 'Shipping only', 'woocommerce' ),
'none' => _x( 'None', 'Tax status', 'woocommerce' ),
);
echo $args[$product->get_tax_status()];
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.
Related: Add custom columns to admin products list in WooCommerce 3
Related
I created 2 new custom stock statuses:
Out of stock (Permanent)
Out of stock (Supplier)
As you can guess, I want them both to be treated as out of stock.
I used some extra code to hide the products with these custom statuses from the front end but I can not hide them from the ajax search (live) and also someone can add the product in cart.
(I use the Flatsome theme and the live search is from there)
Based on: How to add custom stock status to products in WooCommerce 4+
& Hide all products with a specific stock status from WooCommerce catalog, this is my code attempt:
// Add new stock status options
function filter_woocommerce_product_stock_status_options( $status ) {
// Add new statuses
$status['permanent'] = __( 'Out of stock (Permanent)', 'woocommerce' );
$status['supplier'] = __( 'Out of stock (Supplier)', 'woocommerce' );
return $status;
}
add_filter( 'woocommerce_product_stock_status_options', 'filter_woocommerce_product_stock_status_options', 10, 1 );
// Availability text
function filter_woocommerce_get_availability_text( $availability, $product ) {
// Get stock status
switch( $product->get_stock_status() ) {
case 'permanent':
$availability = __( 'Out of stock (Permanent)', 'woocommerce' );
break;
case 'supplier':
$availability = __( 'Out of stock (Supplier)', 'woocommerce' );
break;
}
return $availability;
}
add_filter( 'woocommerce_get_availability_text', 'filter_woocommerce_get_availability_text', 10, 2 );
// Availability CSS class
function filter_woocommerce_get_availability_class( $class, $product ) {
// Get stock status
switch( $product->get_stock_status() ) {
case 'permanent':
$class = 'permanent';
break;
case 'supplier':
$class = 'supplier';
break;
}
return $class;
}
add_filter( 'woocommerce_get_availability_class', 'filter_woocommerce_get_availability_class', 10, 2 );
// Admin stock html
function filter_woocommerce_admin_stock_html( $stock_html, $product ) {
// Simple
if ( $product->is_type( 'simple' ) ) {
// Get stock status
$product_stock_status = $product->get_stock_status();
// Variable
} elseif ( $product->is_type( 'variable' ) ) {
foreach( $product->get_visible_children() as $variation_id ) {
// Get product
$variation = wc_get_product( $variation_id );
// Get stock status
$product_stock_status = $variation->get_stock_status();
}
}
// Stock status
switch( $product_stock_status ) {
case 'permanent':
$stock_html = '<mark class="permanent" style="background:transparent none;color:#33ccff;font-weight:700;line-height:1;">' . __( 'Out of stock (Permanent)', 'woocommerce' ) . '</mark>';
break;
case 'supplier':
$stock_html = '<mark class="supplier" style="background:transparent none;color:#cc33ff;font-weight:700;line-height:1;">' . __( 'Out of stock (Supplier)', 'woocommerce' ) . '</mark>';
break;
}
return $stock_html;
}
add_filter( 'woocommerce_admin_stock_html', 'filter_woocommerce_admin_stock_html', 10, 2 );
//hide specific stock status
add_action( 'woocommerce_product_query_meta_query', 'custom_product_query_meta_query', 1000 );
function custom_product_query_meta_query( $meta_query ) {
if ( ! is_admin() ) {
$meta_query[] = array(
'key' => '_stock_status',
'value' => 'permanent',
'compare' => '!=',
);
}
if ( ! is_admin() ) {
$meta_query[] = array(
'key' => '_stock_status',
'value' => 'supplier',
'compare' => '!=',
);
}
return $meta_query;
}
Any advice on how to handle both custom stock statuses as out of stock?
Since you indicate in your question that your custom stock statuses should contain the same functionality as the current 'outofstock' status, you can instead of rewrite/reuse all existing functionality of the 'outofstock' status for your custom stock statuses, use a workaround.
This will offer a simple solution, since otherwise you would have to overwrite some template files in addition to writing custom code.
The workaround can be applied as follows:
Step 1) add an extra custom field for your custom statuses, we will add this field under the existing stock status field:
// Add custom field
function action_woocommerce_product_options_stock_status() {
// Custom stock status
$options = array(
'empty' => __( 'N/A', 'woocommerce' ),
'permanent' => __( 'Permanent', 'woocommerce' ),
'supplier' => __( 'Supplier', 'woocommerce' ),
);
woocommerce_wp_select(
array(
'id' => '_custom_stock_status',
'wrapper_class' => 'stock_status_field hide_if_variable hide_if_external hide_if_grouped',
'label' => __( 'Custom stock status', 'woocommerce' ),
'options' => $options,
'desc_tip' => true,
'description' => __( 'Your description', 'woocommerce' ),
)
);
}
add_action( 'woocommerce_product_options_stock_status', 'action_woocommerce_product_options_stock_status', 10 );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_custom_stock_status'] ) ) {
// Update
$product->update_meta_data( '_custom_stock_status', sanitize_text_field( $_POST['_custom_stock_status'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
Result:
Step 2) when the product is 'out of stock', we will check whether a custom stock status has been set. If this is the case, we will visually change the text using the code below, so that the customer can see the new status. In the background/backend, however, the 'out of stock' status is still used and therefore automatically also the existing functionality:
// Availability text
function filter_woocommerce_get_availability_text( $availability, $product ) {
// Only for 'outofstock'
if ( $product->get_stock_status() == 'outofstock' ) {
// Get custom stock status
$custom_stock_status = $product->get_meta( '_custom_stock_status' );
// Compare and apply new text
if ( $custom_stock_status == 'permanent' ) {
$availability = __( 'Out of stock (Permanent)', 'woocommerce' );
} elseif ( $custom_stock_status == 'supplier' ) {
$availability = __( 'Out of stock (Supplier)', 'woocommerce' );
}
}
return $availability;
}
add_filter( 'woocommerce_get_availability_text', 'filter_woocommerce_get_availability_text', 10, 2 );
In Woocommerce, I'm attempting to add a piece of custom meta to my products and I would like to pass it through to orders.
We have a substantial amount of products and they are accountable to different cost centers so I need a select box inside the product admin that we can choice the cost centers that passes a value into an order this does not need to be viewed by the customer but needs to be viewable by admin in the orders and also in the order exports each month for accounting.
This is what I have so far, this will display the select box in product edit pages (admin):
// Display Fields
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">';
woocommerce_wp_select(
array(
'id' => '_select',
'label' => __( 'Cost Centre', 'woocommerce' ),
'options' => array(
'one' => __( 'MFEG', 'woocommerce' ),
'two' => __( 'YDIT', 'woocommerce' ),
)
)
);
echo '</div>';
}
// Save Fields
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
// Select
$woocommerce_select = $_POST['_select'];
if( !empty( $woocommerce_select ) )
update_post_meta( $post_id, '_select', esc_attr( $woocommerce_select ) );
}
But it is not passing the value in to an order.
How can I pass this custom field value to the order?
I have revisited a bit your code. The following will save your product custom field "Cost centre" as hidden order item meta data, visible only in Admin Order edit pages on each item:
// Admin products: Display custom Field
add_action( 'woocommerce_product_options_general_product_data', 'product_options_general_product_data_add_field' );
function product_options_general_product_data_add_field() {
global $post;
echo '<div class="options_group">';
woocommerce_wp_select( array(
'id' => '_cost_centre',
'label' => __( 'Cost Centre', 'woocommerce' ),
'options' => array(
'MFEG' => __( 'MFEG', 'woocommerce' ), // Default displayed option value
'YDIT' => __( 'YDIT', 'woocommerce' ),
)
) );
echo '</div>';
}
// Admin products: Save custom Field
add_action( 'woocommerce_process_product_meta', 'product_options_general_product_data_save_field' );
function product_options_general_product_data_save_field( $post_id ){
if( isset( $_POST['_cost_centre'] ) )
update_post_meta( $post_id, '_cost_centre', esc_attr( $_POST['_cost_centre'] ) );
}
// Order items: Save product "Cost centre" as hidden order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'save_file_type_as_order_item_meta', 20, 4);
function save_file_type_as_order_item_meta($item, $cart_item_key, $values, $order) {
if ( $cost_centre = $values['data']->get_meta('_cost_centre') ) {
$item->update_meta_data( '_cost_centre', $cost_centre ); // Save as order item (visble on admin only)
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Export: (In StackOverFlow, the rule is one question for one answer).
The WordPress/Woocommerce basic order export don't allow to export order items
You will need to use a third party plugin and depending on the chosen plugin, you will have to add your order item custom field _cost_centre for your export based on the plugin possibilities.
I'm trying to rename multiple WooCommerce order status by editing my theme's functions.php file. I found some code posted here a couple years ago that works to change a single order status, but since I'm very inexperienced with php, I don't know how to expand on it to change multiple statuses. Ideally I'd also like to rename 'wc-processing' to 'Paid' and 'wc-on-hold' to 'Pending'.
Here's the code I found to edit a single order status:
function wc_renaming_order_status( $order_statuses ) {
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-completed' === $key ) {
$order_statuses['wc-completed'] = _x( 'Order Received', 'Order status', 'woocommerce' );
}
}
return $order_statuses;
}
add_filter( 'wc_order_statuses', 'wc_renaming_order_status' );
Anyone know what changes I need to make to change additional statuses?
As Pending order status exist, you need also to rename the existing "Pending" status. If not you will get 2 different statuses with the same "Pending" label.
First to rename those order statuses:
add_filter( 'wc_order_statuses', 'rename_order_statuses', 20, 1 );
function rename_order_statuses( $order_statuses ) {
$order_statuses['wc-completed'] = _x( 'Order Received', 'Order status', 'woocommerce' );
$order_statuses['wc-processing'] = _x( 'Paid', 'Order status', 'woocommerce' );
$order_statuses['wc-on-hold'] = _x( 'Pending', 'Order status', 'woocommerce' );
$order_statuses['wc-pending'] = _x( 'Waiting', 'Order status', 'woocommerce' );
return $order_statuses;
}
And Also in the bulk edit order list dropdown:
add_filter( 'bulk_actions-edit-shop_order', 'custom_dropdown_bulk_actions_shop_order', 20, 1 );
function custom_dropdown_bulk_actions_shop_order( $actions ) {
$actions['mark_processing'] = __( 'Mark paid', 'woocommerce' );
$actions['mark_on-hold'] = __( 'Mark pending', 'woocommerce' );
$actions['mark_completed'] = __( 'Mark order received', 'woocommerce' );
return $actions;
}
And also this is needed (for the top menu):
foreach( array( 'post', 'shop_order' ) as $hook )
add_filter( "views_edit-$hook", 'shop_order_modified_views' );
function shop_order_modified_views( $views ){
if( isset( $views['wc-completed'] ) )
$views['wc-completed'] = str_replace( 'Completed', __( 'Order Received', 'woocommerce'), $views['wc-completed'] );
if( isset( $views['wc-processing'] ) )
$views['wc-processing'] = str_replace( 'Processing', __( 'Paid', 'woocommerce'), $views['wc-processing'] );
if( isset( $views['wc-on-hold'] ) )
$views['wc-on-hold'] = str_replace( 'On hold', __( 'Pending', 'woocommerce'), $views['wc-on-hold'] );
if( isset( $views['wc-pending'] ) )
$views['wc-pending'] = str_replace( 'Pending', __( 'Stucked', 'woocommerce'), $views['wc-pending'] );
return $views;
}
(Thanks to brasofilo : Change WP admin post status filter for custom post type)
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Since Woocommerce 3.3 to handle the preview popup (eye symbol) in admin order list:
Replace order status names everywhere incl. Woocommerce admin order preview
We use the following function.php code below to offer a multi choice field in checkout. We add it to the order page and include it in the email.
How can we include it in the ORDERs overview admin page as well, make it searchable and sortable ?
// add select box for platform used at checkout
add_action('woocommerce_after_order_notes', 'wps_add_select_checkout_field');
function wps_add_select_checkout_field( $checkout ) {
echo '<h3>'.__('').'</h3>';
woocommerce_form_field( 'platform', array(
'type' => 'select',
'class' => array( 'wps-drop' ),
'label' => __( 'On which platform will you be using it?' ),
'options' => array(
'blank' => __( '-- Choose an option --', 'wps' ),
'app1' => __( 'app1', 'wps' ),
'app2' => __( 'app2', 'wps' ),
'app3' => __( 'app3', 'wps' )
)
), $checkout->get_value( 'platform' ) );
}
// Process the checkout
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['platform'] == "blank")
wc_add_notice( '<strong>Please select your primary trading platform that you will be using with our strategy</strong>', 'error' );
}
// Update the order meta with field value
add_action('woocommerce_checkout_update_order_meta', 'wps_select_checkout_field_update_order_meta');
function wps_select_checkout_field_update_order_meta( $order_id ) {
if ($_POST['platform']) update_post_meta( $order_id, 'platform', esc_attr($_POST['platform']));
}
// Display field value on the order edition page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'wps_select_checkout_field_display_admin_order_meta', 10, 1 );
function wps_select_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Primary Platform').':</strong> ' . get_post_meta( $order->id, 'platform', true ) . '</p>';
}
// Add selection field value to emails
add_filter('woocommerce_email_order_meta_keys', 'wps_select_order_meta_keys');
function wps_select_order_meta_keys( $keys ) {
$keys['platform:'] = 'platform';
return $keys;
}
Here is the way to add a custom column 'Platform' in Admin WooCommerce Orders list and to add this custom field meta key in the search:
// ADDING A CUSTOM COLUMN TITLE TO ADMIN ORDER LIST
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
// Set "Actions" column after the new colum
$action_column = $columns['order_actions']; // Set the title in a variable
unset($columns['order_actions']); // remove "Actions" column
//add the new column "Platform"
$columns['order_platform'] = '<span>'.__( 'Platform','woocommerce').'</span>'; // title
// Set back "Actions" column
$columns['order_actions'] = $action_column;
return $columns;
}
// ADDING THE DATA FOR EACH ORDERS BY "Platform" COLUMN
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id )
{
// HERE get the data from your custom field (set the correct meta key below)
$platform = get_post_meta( $post_id, 'platform', true );
if( empty($platform)) $platform = '';
switch ( $column )
{
case 'order_platform' :
echo '<span>'.$platform.'</span>'; // display the data
break;
}
}
// MAKE 'PLATFORM' METAKEY SEARCHABLE IN THE SHOP ORDERS LIST
add_filter( 'woocommerce_shop_order_search_fields', 'platform_search_fields', 10, 1 );
function platform_search_fields( $meta_keys ){
$meta_keys[] = 'platform';
return $meta_keys;
}
Code goes in function.php file of your active child theme (active theme or in any plugin file).
Tested and works.
I would like to rename the WooCommerce order status from "Completed" to "Order Received". I can edit the script below located in wc-order-functions.php, but I would prefer not to modify any core files or use a plugin.
Is it possible to override woocoomerce functions with scripts in child theme's functions.php file?
function wc_get_order_statuses() {
$order_statuses = array(
'wc-pending' => _x( 'Pending Payment', 'Order status', 'woocommerce' ),
'wc-processing' => _x( 'Processing', 'Order status', 'woocommerce' ),
'wc-on-hold' => _x( 'On Hold', 'Order status', 'woocommerce' ),
'wc-completed' => _x( 'Completed', 'Order status', 'woocommerce' ),
'wc-cancelled' => _x( 'Cancelled', 'Order status', 'woocommerce' ),
'wc-refunded' => _x( 'Refunded', 'Order status', 'woocommerce' ),
'wc-failed' => _x( 'Failed', 'Order status', 'woocommerce' ),
);
return apply_filters( 'wc_order_statuses', $order_statuses );
}
Just renaming order status "Completed" to "Order Received", it's easy and can be accomplished this way with wc_order_statuses hook (you will paste this snippet in your active child theme function.php file):
add_filter( 'wc_order_statuses', 'wc_renaming_order_status' );
function wc_renaming_order_status( $order_statuses ) {
foreach ( $order_statuses as $key => $status ) {
if ( 'wc-completed' === $key )
$order_statuses['wc-completed'] = _x( 'Order Received', 'Order status', 'woocommerce' );
}
return $order_statuses;
}
Code goes in function.php file of your active child theme (or active theme). Tested and Works.
Update 2018 - To rename, in Order list page:
• the bulk actions dropdown
• the order status tabs (with the count)
See: Rename multiple order statuses in Woocommerce
Other related reference: How to create a custom order status in woocommerce
The accepted answer does a good job in most places, but the order status filter on the main order page is unaffected, as mentioned in one of the comments.
To update this you must also hook into the filter woocommerce_register_shop_order_post_statuses and update label_count like so:
// Rename order status 'Completed' to 'Order Received' in admin main view - different hook, different value than the other places
function wc_rename_order_status_type( $order_statuses ) {
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-completed' === $key ) {
$order_statuses['wc-completed']['label_count'] = _n_noop( 'Order Received <span class="count">(%s)</span>', 'Order Received <span class="count">(%s)</span>', 'woocommerce' );
}
}
return $order_statuses;
}
add_filter( 'woocommerce_register_shop_order_post_statuses', 'wc_rename_order_status_type' );
You will also need to update the string in the 'Bulk Actions' dropdown. Hooking into WordPress' gettext filter let's you do it, like so:
// Rename order status in the bulk actions dropdown on main order list
function rename_bulk_status( $translated_text, $untranslated_text, $domain ) {
if( is_admin()) {
if( $untranslated_text == 'Change Status To completed' )
$translated_text = __( 'Change Status To Order Received','woocommerce' );
}
return $translated_text;
}
add_filter('gettext', 'rename_bulk_status', 20, 3);
So add these to the accepted answer above so you have all 3 functions.
I had a similar wish, but for some reason Loic's solution did not work with my shop. So I want to share my simple solution.
With the free plugin LocoTranslate you can easily rename the order status for your language. If your page needs no translation (i.e. it is in English), it might still be handy.
Simply create a totally new translation file and enter only the new order status replacing the original name. All other terms are not affected by this language file, if the fields stay empty (don't forget to activate this pseudo-translation in page settings).
This way, there is a good chance that WooCommerce updates will not affect it.
Go to plugin Editor -> choose WooCommerce -> includes -> admin -> class-wc-admin-dashboard.php (Edit Line 45)
DO NOT COPY PASTE THE CONTENT FROM HERE. FIND & REPLACE
Default-----------------------
public function init() {
// Reviews Widget.
if ( current_user_can( 'publish_shop_orders' ) && post_type_supports( 'product', 'comments' ) ) {
wp_add_dashboard_widget( 'woocommerce_dashboard_recent_reviews', __( 'WooCommerce Recent Reviews', 'woocommerce' ), array( $this, 'recent_reviews' ) );
}
wp_add_dashboard_widget( 'woocommerce_dashboard_status', __( 'WooCommerce Status', 'woocommerce' ), array( $this, 'status_widget' ) );
Edited--------------
public function init() {
// Reviews Widget.
if ( current_user_can( 'publish_shop_orders' ) && post_type_supports( 'product', 'comments' ) ) {
wp_add_dashboard_widget( 'woocommerce_dashboard_recent_reviews', __( 'WooCommerce Recent Reviews', 'woocommerce' ), array( $this, 'recent_reviews' ) );
}
wp_add_dashboard_widget( 'woocommerce_dashboard_status', __( 'Shop Status', 'woocommerce' ), array( $this, 'status_widget' ) );