I've got a question - is it possible to add one more column (which will present data from custom field) to csv export file in woocommerce? all necessary data is stored for each order as meta_key: 'authors_income'. I have no idea how to make it. I've tried to adapt below code, but it doesnt work:
function wpg_add_columns($cols) {
$cols['wc_settings_tab_payment_method'] = __('Payment Method', 'mytheme');
return $cols;
}
add_filter('wpg_order_columns', 'wpg_add_columns');
This should work. Let me know this goes.
<?php
//Step 1: Add field to column
function wpg_add_columns($cols) {
$cols['wc_settings_tab_authors_income'] = __('Authors Income', 'mytheme');
return $cols;
}
add_filter('wpg_order_columns', 'wpg_add_columns');
//Step 2: Add same column to settings, so that it will appear in settings page.
function wpg_add_fields($settings) {
$settings['authors_income'] = array(
'name' => __( 'Authors Income', 'woocommerce-simply-order-export' ),
'type' => 'checkbox',
'desc' => __( 'Authors Income', 'woocommerce-simply-order-export' ),
'id' => 'wc_settings_tab_authors_income'
);
return $settings;
}
add_filter('wc_settings_tab_order_export', 'wpg_add_fields');
//Note: Notice that in above step, id attribute is identical to that of array key in step 1. ( wc_settings_tab_authors_income )
//Step 3: Add it to csv.
function csv_write( &$csv, $od, $fields ) {
if( !empty( $fields['wc_settings_tab_authors_income'] ) && $fields['wc_settings_tab_authors_income'] === true ){
$authors_income = get_post_meta( $od->id, 'authors_income', true );
array_push( $csv, $authors_income );
}
}
add_action('wpg_add_values_to_csv', 'csv_write', 10, 3);
Related
I need a custom fields on the inventory tab that will be filled in with the zipcode as the location of the agent.
Armed with the references I got here, now I have that field.
what I want to ask is how to concatenate this meta data with woocommerce shortcode?
I think like :
['products limit="12" columns="4" zipcode="12345"]
where "12345" will be changing dynamically as needed (zipcode filled based on agent location).
I have tried to do something but it is not working properly.
Here's the full code.
function action_woocommerce_product_options_inventory_product_data_zipcode() {
woocommerce_wp_text_input( array(
'id' => '_zipcode',
'label' => __( 'Zipcode', 'woocommerce' ),
'description' => __( 'Please fill your zipcode.', 'woocommerce' ),
'desc_tip' => 'true',
'placeholder' => __( '12345', 'woocommerce' )
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data_zipcode' );
// Save zipcode
function action_woocommerce_admin_process_product_object_zipcode( $product ) {
// Isset
if ( isset( $_POST['_zipcode'] ) ) {
// Update
$product->update_meta_data( '_zipcode', sanitize_text_field( $_POST['_zipcode'] ));
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object_zipcode', 10, 1 );
Try put to shortcode products :
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = true;
} else {
$out['zipcode'] = false;
}
return $out;
}
add_filter( 'shortcode_atts_products', 'filter_shortcode_atts_products_zipcode', 10, 4);
function filter_woocommerce_shortcode_products_query_zipcode( $query_args, $atts, $type) {
if ( $type == 'products' && $atts['zipcode'] ) {
// Meta query
$query_args['meta_query'] = array(
array(
'key' => '_zipcode',
'value' => $atts['zipcode'],
'compare' => 'LIKE',
)
);
}
return $query_args;
}
add_filter( 'woocommerce_shortcode_products_query', 'filter_woocommerce_shortcode_products_query_zipcode', 10, 3 );
On testing I tried :
['products limit="12" columns="4" zipcode="12345"]
shortcode has displayed the product but does not refer to the postal code in the short code ("12345") but to all products that have a postal code.
Can somebody help me?
Thank you
Something doesn't feel right about the shortcode attribute function. I think you're setting the attribute as true and therefore it's comparing anything "truthy." Maybe just try setting the true one as the zipcode, like this:
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = $atts['zipcode'];
} else {
$out['zipcode'] = false;
}
return $out;
}
That way it'll return the zipcode if it exists, and false if it doesn't, which the query can then use for the comparison.
I have tried modifying the answer provided in //stackoverflow.com/a/59544491/19984414. I am not getting any errors when testing it, but also nothing really happens to my test order.
How can I test, why nothing happens when I make an order?
add_action( 'woocommerce_checkout_order_processed', 'action_woocommerce_checkout_order_processed', 10, 3 );
function action_woocommerce_checkout_order_processed( $order_id, $posted_data, $order ) {
// Initialize
$check_for_stock = false;
$taxonomy = 'product_tag';
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Get product
$product = $item->get_product();
// Product has tag 'stock'
if ( has_term( 'stock', $taxonomy, $product ) ) {
// Will only be executed once if the order contains line items with tag "stock"
if ( $check_for_stock == false ) {
$check_for_stock = true;
// Create new order with stock items
$stock_order = wc_create_order();
}
// Add product to 'backorder' order
$stock_order->add_product( $product, $item['quantity'] );
$stock_order->save();
// Delete item from original order
$order->remove_item( $item->get_id() );
}
}
// If current order contains line items with product tag "stock", retrieve the necessary data from the existing order and apply it in the new order
if ( $check_for_stock ) {
// Recalculate and save original order
$order->calculate_totals();
$order->save();
// Obtain necessary information
// Get address
$address = array(
'first_name' => $order->get_billing_first_name(),
'last_name' => $order->get_billing_last_name(),
'email' => $order->get_billing_email(),
'phone' => $order->get_billing_phone(),
'address_1' => $order->get_billing_address_1(),
'address_2' => $order->get_billing_address_2(),
'city' => $order->get_billing_city(),
'state' => $order->get_billing_state(),
'postcode' => $order->get_billing_postcode(),
'country' => $order->get_billing_country()
);
// Get shipping
$shipping = array(
'first_name' => $order->get_shipping_first_name(),
'last_name' => $order->get_shipping_last_name(),
'address_1' => $order->get_shipping_address_1(),
'address_2' => $order->get_shipping_address_2(),
'city' => $order->get_shipping_city(),
'state' => $order->get_shipping_state(),
'postcode' => $order->get_shipping_postcode(),
'country' => $order->get_shipping_country()
);
// Get order currency
$currency = $order->get_currency();
// Get order payment method
$payment_gateway = $order->get_payment_method();
// Required information has been obtained, assign it to the 'backorder' order
// Set address
$stock_order->set_address( $address, 'billing' );
$stock_order->set_address( $shipping, 'shipping' );
// Set the correct currency and payment gateway
$stock_order->set_currency( $currency );
$stock_order->set_payment_method( $payment_gateway );
// Calculate totals
$stock_order->calculate_totals();
// Set order note with original ID
$stock_order->add_order_note( 'Automated "stock" order. Created from the original order ID: ' . $order_id );
// Optional: give the new 'backorder' order the correct status
$stock_order->update_status( 'on-hold' );
$stock_order->save();
}
}
I am running the snippet from WPCodeBox with the following (default) settings:
How to run the snippet: Always (On Page Load)
Hook/Priority: Root (Default)
Snippet Order: 10
Where to run the snippet: Everywhere
I'm using the following code in my theme functions.php file to add a additional data field to the product inventory tab:
// Add Custom Field to woocommerce inventory tab for product
add_action('woocommerce_product_options_inventory_product_data', function() {
woocommerce_wp_text_input([
'id' => '_number_in_package',
'label' => __('Number of Pages', 'txtdomain'),
'type' => 'number',
]);
});
add_action('woocommerce_process_product_meta', function($post_id) {
$product = wc_get_product($post_id);
$num_package = isset($_POST['_number_in_package']) ? $_POST['_number_in_package'] : '';
$product->update_meta_data('_number_in_package', sanitize_text_field($num_package));
$product->save();
});
add_action('woocommerce_product_meta_start', function() {
global $post;
$product = wc_get_product($post->ID);
$num_package = $product->get_meta('_number_in_package');
if (!empty($num_package)) {
printf('<div class="custom-sku">%s: %s</div>', __('Number of Pages', 'txtdomain'), $num_package);
}
});
add_filter('woocommerce_product_data_tabs', function($tabs) {
$tabs['additional_info'] = [
'label' => __('Additional info', 'txtdomain'),
'target' => 'additional_product_data',
'class' => ['hide_if_external'],
'priority' => 25
];
return $tabs;
});
However, on the single product page, the custom field is added before category and ISBN. I want to place the custom field at the end after the product ISBN. Any advice?
Some comments/suggestions regarding your code attempt
To save fields you can use the woocommerce_admin_process_product_object hook, opposite the outdated woocommerce_process_product_meta hook
WooCommerce contains by default no ISBN field, but it looks like the woocommerce_product_meta_end hook will answer your question
So you get:
// Add custom field
function action_woocommerce_product_options_inventory_product_data() {
woocommerce_wp_text_input( array(
'id' => '_number_in_package',
'label' => __( 'Number of Pages', 'woocommerce' ),
'description' => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
'desc_tip' => 'true',
'type' => 'number'
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data' );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_number_in_package'] ) ) {
// Update
$product->update_meta_data( '_number_in_package', sanitize_text_field( $_POST['_number_in_package'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Display on single product page
function action_woocommerce_product_meta_end() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$number = $product->get_meta( '_number_in_package' );
// NOT empty
if ( ! empty ( $number ) ) {
echo '<p>' . $number . '</p>';
}
}
}
add_action( 'woocommerce_product_meta_end', 'action_woocommerce_product_meta_end', 10 );
I have a bug with the edit quantity in an order while using a custom status. The edit arrow seems to have disappeared?
Is there another value I can include while registering a custom order status?
Here is my code:
// Register new status 'To order'
function register_new_on_hold_order_status2() {
register_post_status( 'wc-to-order', array(
'label' => 'To order',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'To order (%s)', 'To order (%s)' )
) );
}
add_action( 'init', 'register_new_on_hold_order_status2' );
// Add to list of WC Order statuses
function add_on_hold_new_to_order_statuses2( $order_statuses ) {
$new_order_statuses = array();
// add new order status after processing
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) { // Here we Define after which to be added
$new_order_statuses['wc-to-order'] = 'To order';
}
}
return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_on_hold_new_to_order_statuses2' );
This is not a bug, certain order statuses such as processing do not allow the order to be editable. To change this you can use the wc_order_is_editable hook
So you get:
function filter_wc_order_is_editable( $editable, $order ) {
// Compare
if ( $order->get_status() == 'your-status' ) {
$editable = true;
}
return $editable;
}
add_filter( 'wc_order_is_editable', 'filter_wc_order_is_editable', 10, 2 );
Note: use woocommerce_register_shop_order_post_statuses
opposite init while registering a custom order status as applied in the 2nd part of this answer
I spent so much time to figure this out. How do automatically fill defaults values on the field or inserted into database upon installing the plugin.
I have tried these following codes but nothing works:
register_activation_hook(__FILE__, 'just_a_handler');
function just_a_handler($plugin_options) {
$defaults = array(
'youtube_keyword' => 'keyword here',
'youtube_author' => 'author here',
'youtube_content' => 'by_keyword',
'youtube_width' => '500',
'youtube_height' => '350',
'youtube_number_of_videos' => '5',
'youtube_preview' => '',
);
$plugin_options = wp_parse_args(get_option('youtube_plugin_options'), $defaults);
}
and this one:
register_activation_hook(__FILE__, 'just_a_handler');
function just_a_handler() {
add_option("youtube_keyword", 'keyword here', '', 'yes');
add_option("youtube_author", 'author here', '', 'yes');
}
To automatically fill an option with some defaults you can do something like the following. Depending on when you execute this code, I think it's a good idea to check that the option doesn't already exist before filling it with the default data. Also keep in mind that if you're storing an array, you need to serialize your data before adding it to the database. Databases can only store numbers, text, and dates. Serialization takes an array and turns it into a serialized string.
function init_options() {
$retrieved_options = array();
$defaults = array(
'youtube_keyword' => 'keyword here',
'youtube_author' => 'author here',
'youtube_content' => 'by_keyword',
'youtube_width' => '500',
'youtube_height' => '350',
'youtube_number_of_videos' => '5',
'youtube_preview' => '',
);
// Check to see if the option exists
$retrieved_options = maybe_unserialize( get_option( 'youtube_plugin_options' ) );
if ( $retrieved_options == '' ) {
// There are no options set
add_option( 'youtube_plugin_options', serialize( $defaults ) );
} elseif ( count( $retrieved_options ) == 0 ) {
// All options are blank
update_option( 'youtube_plugin_options', serialize( $defaults ) );
}
}
register_activation_hook( __FILE__, 'init_options' );