I Hope are you okay.
Today I have problems with I open order invoice pdf in admin after products list have components.
I Remove all components as well
I am using woocommerce-pdf-invoices-packing-slips plugin.
Below is my product URL :
https://www.pcguru.lt/produktas/amd-home-guru/
My Invoice PDF screenshot as well.
How can I remove it?
I Searching Google but couldn't Found Anything.
After Code Debugging Step by Step, That's are Found Successfully.
File Path:
/wp-content/plugins/woocommerce-pdf-invoices-packing-slips/includes/documents/abstract-wcpdf-order-document-methods.php
public function get_order_items() {
$items = $this->order->get_items();
$data_list = array();
if( sizeof( $items ) > 0 ) {
foreach ( $items as $item_id => $item ) {
//Find Child Product Of Composite Product
global $wpdb;
$post_id = $wpdb->get_row("SELECT meta_value FROM pcg_woocommerce_order_itemmeta WHERE (meta_key = 'wooco_ids' AND order_item_id = '". $item_id ."')");
if($post_id->meta_value !=''){
$main_id = str_replace('/1/', '', $post_id->meta_value);
$data_ids = explode(",",$main_id);
}
//END Custom Code
$data = array();
// Set the item_id
$data['item_id'] = $item_id;
// Set the id
$data['product_id'] = $item['product_id'];
$data['variation_id'] = $item['variation_id'];
// Compatibility: WooCommerce Composit Products uses a workaround for
// setting the order before the item name filter, so we run this first
if ( class_exists('WC_Composite_Products') ) {
$order_item_class = apply_filters( 'woocommerce_order_item_class', '', $item, $this->order );
}
// Set item name
$data['name'] = apply_filters( 'woocommerce_order_item_name', $item['name'], $item, false );
// Set item quantity
$data['quantity'] = $item['qty'];
//$data['product_desc'] = $item->get_product(); // Get the WC_Product objec
//echo '<pre>'; print_r($product); echo '</pre>'; die;
// Set the line total (=after discount)
$data['line_total'] = $this->format_price( $item['line_total'] );
$data['single_line_total'] = $this->format_price( $item['line_total'] / max( 1, abs( $item['qty'] ) ) );
$data['line_tax'] = $this->format_price( $item['line_tax'] );
$data['single_line_tax'] = $this->format_price( $item['line_tax'] / max( 1, abs( $item['qty'] ) ) );
$data['tax_rates'] = $this->get_tax_rate( $item, $this->order, false );
$data['calculated_tax_rates'] = $this->get_tax_rate( $item, $this->order, true );
// Set the line subtotal (=before discount)
$data['line_subtotal'] = $this->format_price( $item['line_subtotal'] );
$data['line_subtotal_tax'] = $this->format_price( $item['line_subtotal_tax'] );
$data['ex_price'] = $this->get_formatted_item_price( $item, 'total', 'excl' );
$data['price'] = $this->get_formatted_item_price( $item, 'total' );
$data['order_price'] = $this->order->get_formatted_line_subtotal( $item ); // formatted according to WC settings
// Calculate the single price with the same rules as the formatted line subtotal (!)
// = before discount
$data['ex_single_price'] = $this->get_formatted_item_price( $item, 'single', 'excl' );
$data['single_price'] = $this->get_formatted_item_price( $item, 'single' );
// Pass complete item array
$data['item'] = $item;
// Get the product to add more info
if ( is_callable( array( $item, 'get_product' ) ) ) {
$product = $item->get_product();
} else {
$product = $this->order->get_product_from_item( $item );
}
// Checking fo existance, thanks to MDesigner0
if( !empty( $product ) ) {
// Thumbnail (full img tag)
$data['thumbnail'] = $this->get_thumbnail( $product );
$data['get_parent_id'] = is_callable( array( $product, 'get_parent_id' ) ) ? $product->get_parent_id() : '';
// Set item SKU
$data['sku'] = is_callable( array( $product, 'get_sku' ) ) ? $product->get_sku() : '';
// Set item weight
$data['weight'] = is_callable( array( $product, 'get_weight' ) ) ? $product->get_weight() : '';
// Set item dimensions
$data['dimensions'] = $product instanceof \WC_Product ? WCX_Product::get_dimensions( $product ) : '';
// Pass complete product object
$data['product'] = $product;
} else {
$data['product'] = null;
}
// Set item meta
if (function_exists('wc_display_item_meta')) { // WC3.0+
$data['meta'] = wc_display_item_meta( $item, array(
'echo' => false,
) );
} else {
if ( version_compare( WOOCOMMERCE_VERSION, '2.4', '<' ) ) {
$meta = new \WC_Order_Item_Meta( $item['item_meta'], $product );
} else { // pass complete item for WC2.4+
$meta = new \WC_Order_Item_Meta( $item, $product );
}
$data['meta'] = $meta->display( false, true );
}
if (!in_array($data['product_id'], $data_ids)) {
$data_list[$item_id] = apply_filters( 'wpo_wcpdf_order_item_data', $data, $this->order, $this->get_type());
}
}
}
//echo '<pre>'; print_r($data_list); echo '</pre>'; die;
return apply_filters( 'wpo_wcpdf_order_items_data', $data_list, $this->order, $this->get_type() );
}
Solution Screenshot:
I am very happy because solution are completed.
Also Thanks to all helping guys
Related
I want to export order data in xml when order is created. and i already applied that but i am getting problem when getting order data tax for each items specially tax rate labels example. "7% Mswt", "19% Mswt".
function get_line_items( $order ) {
$items = [];
/** #var \WC_Order_Item_Product $line_items */
$line_items = $order->get_items( 'line_item' );
// loop through each item in order
foreach ( $line_items as $item_id => $item ) {
// get the product
/** #var \WC_Product $product */
$product = $item->get_product();
// instantiate line item meta
$meta_data = $item->get_formatted_meta_data( '_', true );
$display_meta = [];
foreach ( $meta_data as $meta ) {
$display_meta[] = "{$meta->display_key}: {$meta->display_value}";
}
$item_meta = implode( ', ', $display_meta );
// remove all HTML
$item_meta = wp_strip_all_tags( $item_meta );
// strip HTML in legacy format - note: in modern formats,
// SV_WC_Helper::array_to_xml will automatically escape HTML and newlines by wrapping
// the contents of the tag in CDATA when necessary
if ( 'legacy' === $this->export_format ) {
// remove control characters
$item_meta = str_replace( [ "\r", "\n", "\t" ], '', $item_meta );
}
// remove any html entities
$item_meta = preg_replace( '/\&(?:[a-z,A-Z,0-9]+|#\d+|#x[0-9a-f]+);/', '', $item_meta );
$item_data = [];
$item_data['Id'] = $item_id;
$item_data['Name'] = html_entity_decode( $product ? $product->get_title() : $item['name'], ENT_NOQUOTES, 'UTF-8' );
$item_data['ProductId'] = $product ? $product->get_id() : ''; // handling for permanently deleted product
$item_data['SKU'] = $product ? $product->get_sku() : ''; // handling for permanently deleted product
$item_data['Quantity'] = $item['qty'];
$item_data['Price'] = $this->format_decimal( $order->get_item_total( $item ), 2 );
$item_data['Subtotal'] = $this->format_decimal( $order->get_line_subtotal( $item ), 2 );
//$item_data['SubtotalTax'] = $this->format_decimal( $item['line_subtotal_tax'], 2 );
$item_data['Total'] = $this->format_decimal( $order->get_line_total( $item ), 2 );
$item_data['TaxPercentage'] = $item ->get_tax_class()->labels;
$item_data['TotalTax'] = $this->format_decimal( $order->get_line_tax( $item ), 2 );
//$item_data['Refunded'] = $this->format_decimal( $order->get_total_refunded_for_item( $item ), 2 );
//$item_data['RefundedQuantity'] = $order->get_qty_refunded_for_item( $item_id );
/*if ( 'yes' === get_option( 'woocommerce_calc_taxes' ) && 'yes' === get_option( 'woocommerce_prices_include_tax' ) ) {
$item_data['PriceInclTax'] = $this->format_decimal( $order->get_item_total( $item, true ), 2 );
$item_data['TotalInclTax'] = $this->format_decimal( $order->get_line_total( $item, true ), 2 );
}*/
$item_data['Meta'] = $item_meta;
//$item_data['Taxes'] = $this->get_tax_details( $item );
// Keep order items backwards-compatible with legacy version
if ( 'legacy' === $this->export_format ) {
// rename fields to be compatible with pre 2.0.0
$item_data['ItemName'] = $item_data['Name'];
$item_data['LineTotal'] = $item_data['Total'];
if ( 'yes' === get_option( 'woocommerce_calc_taxes' ) && 'yes' === get_option( 'woocommerce_prices_include_tax' ) ) {
$item_data['LineTotalInclTax'] = $item_data['TotalInclTax'];
}
// remove data that wasn't present pre 2.0.0
unset( $item_data['Id'], $item_data['Name'], $item_data['ProductId'], $item_data['Subtotal'], $item_data['SubtotalTax'], $item_data['Total'], $item_data['TotalTax'], $item_data['Refunded'], $item_data['RefundedQuantity'], $item_data['TotalInclTax'], $item_data['Taxes'] );
}
/**
* Allow actors to modify the line item data / format
*
* In 2.0.0 renamed from `wc_customer_order_xml_export_suite_order_export_line_item_format`
* to `wc_customer_order_xml_export_suite_order_line_item`
*
* #since 5.0.0
*
* #param array $item_data
* #param \WC_Order $order Related order
* #param array $item Order line item
*/
$items['OrderLineItem'][] = apply_filters( 'wc_customer_order_export_xml_order_line_item', $item_data, $order, $item );
}
return ! empty( $items ) ? $items : null; }
Can any body guide me please what i am missing here for get tax label for products for to store in xml...
$item_data['TaxPercentage'] = $item ->get_tax_class()->labels;
I was given code from someone on the Wordpress forum, but it isn't quite right.
It has created a column in my Product Admin called Attributes, and it is bringing in the name of the attributes, but not options. i.e. it looks like
"coloursizeyearcountry"
And I would like
"Colour = Red, Size = large, Year = 2020, Country = UK"
or something like it.
The code I have so far is:
function add_product_column( $columns ) {
//add column
$columns['new_column'] = __( 'New column', 'woocommerce' );
return $columns;
}
add_filter( 'manage_edit-product_columns', 'add_product_column', 10, 1 );
function add_product_column_content( $column, $postid ) {
if ( $column == 'new_column' ) {
// Get product object
$product = wc_get_product( $postid );
// Get Product Variations
$product_attributes = $product->get_attributes();
foreach ( $product_attributes as $product_attribute ) {
$attribute_name = $product_attribute->get_name();
echo str_replace( 'pa_', '', $attribute_name );
}
}
}
add_action( 'manage_product_posts_custom_column', 'add_product_column_content', 10, 2 );
The following code will help you get what you want. Explanation via the comment tags added in the code
function add_product_column( $columns ) {
//add column
$columns['new_column'] = __( 'New column', 'woocommerce' );
return $columns;
}
add_filter( 'manage_edit-product_columns', 'add_product_column', 10, 1 );
function add_product_column_content( $column, $postid ) {
if ( $column == 'new_column' ) {
// output variable
$output = '';
// Get product object
$product = wc_get_product( $postid );
// Get Product Variations - WC_Product_Attribute Object
$product_attributes = $product->get_attributes();
// Not empty, contains values
if ( !empty( $product_attributes ) ) {
foreach ( $product_attributes as $product_attribute ) {
// Get name
$attribute_name = str_replace( 'pa_', '', $product_attribute->get_name() );
// Concatenate
$output = $attribute_name . ' = ';
// Get options
$attribute_options = $product_attribute->get_options();
// Not empty, contains values
if ( !empty( $attribute_options ) ) {
foreach ($attribute_options as $key => $attribute_option ) {
// WP_Term Object
$term = get_term($attribute_option); // <-- your term ID
// Not empty, contains values
if ( !empty( $term ) ) {
$term_name = $term->name;
// Not empty
if ( $term_name != '' ) {
// Last loop
end($attribute_options);
if ( $key === key($attribute_options) ) {
// Concatenate
$output .= $term_name;
} else {
// Concatenate
$output .= $term_name . ', ';
}
}
}
}
}
echo $output . '<br>';
}
}
}
}
add_action( 'manage_product_posts_custom_column', 'add_product_column_content', 10, 2 );
I am using this code to send product data to stripe as metadata.
function filter_wc_stripe_payment_metadata( $metadata, $order, $source ) {
$count = 1;
foreach( $order->get_items() as $item_id => $line_item ){
$item_data = $line_item->get_data();
$product = $line_item->get_product();
$location = $product->get_attribute('location');
$product_name = $product->get_name();
$item_quantity = $line_item->get_quantity();
$item_total = $line_item->get_total();
$metadata['Item '.$count] = '';
$count += 1;
}
return $metadata;
}
add_filter( 'wc_stripe_payment_metadata', 'filter_wc_stripe_payment_metadata', 10, 3 );
How can I get the selected variation of the product and add it to the metadata?
$attribute = $product->get_attribute('location'); didn't work for me for some reason. So I used this which works well so far.
foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
$value = $args['autop'] ? wp_kses_post( $meta->display_value ) : wp_kses_post( make_clickable( trim( $meta->display_value ) ) );
$strings[] = $value;
}
$attribute = $strings[1];
$attribute = str_ireplace('<p>','',$attribute);
$attribute = str_ireplace('</p>','',$attribute);
$metadata['Location'] = $attribute;
Bellow I have a custom shortcode function based on this answer code that displays a block of product data for both Simple products and each variation of a Variable product. The output of the variation blocks seems to be ordered by the ID of the variation itself.
For example, this is a screenshot of the frontend output:
Which you can see matches the order of the variation IDs (from smallest to largest) screenshot:
What I would like is to sort the variations by their prices instead (NOT by their IDs) from lowest to highest. Any help is appreciated.
This is the current customized code that I have:
add_shortcode("price_variation_table", "fs_custom_available_variations_table");
function fs_custom_available_variations_table( $atts ) {
global $post;
// Attributes
$atts = shortcode_atts(
array(
'id' => $post->ID
),
$atts, 'price_variation_table'
);
if( is_admin() ) return; // Only on front end
$product = wc_get_product($atts['id']); // Get the WC_Product Object
$output = '<div class="fs-product-data-wrapper">';
// Variable products
if( $product->is_type('variable'))
{
// Get available variations in the variable product
$available_variations = $product->get_available_variations();
if( count($available_variations) > 0 ){
foreach( $available_variations as $variation )
$output .= fs_format_product_data_output( $variation['variation_id'] );
}
}
// Simple products
elseif( $product->is_type('simple'))
{
$output .= fs_format_product_data_output( $product->get_id() );
}
else return; // Exit
return $output .= '</div>'; // return always for a shortcode
}
// Utility funtion: getting and formtting product data
function fs_format_product_data_output( $the_id ){
$empty = __( '<em>(empty)</em>', 'woocommerce' );
// Get an instance of the WC_Product_Variation object
$product = wc_get_product( $the_id );
// Only wc_get_price_to_display() respect if product is to be displayed with or without including taxes
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$sale_price = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
$sale_price = ! empty( $sale_price ) ? wc_price($sale_price) : $empty;
// can use this class is there is no sale price set
if ( ! $product->is_on_sale() ) {
$no_sale_price = ' no-sale-price';
}
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$stock_qty = $product->get_stock_quantity();
$stock_qty = ! empty( $stock_qty ) ? $stock_qty : '0';
if ( $stock_qty <= 0 ) {
$stock_status = 'stock-sold-out';
}
else {
$stock_status = 'stock-available';
}
$output = '
<ul class="'. $stock_status .'">
<li class="fs-data-price">'.$price.' ea.</li>
<li class="fs-data-size">Size: '.$size.'</li>
<li class="fs-data-sale'. $no_sale_price .'">'.$sale_price.' ea. Preferred customer price</li>
<li class="fs-data-stock">Quantity in Stock: '.$stock_qty.'</li>
<li class="fs-data-notice">Quantities change quickly!</li>
</ul>';
return $output;
}
Try the following lightly changed code, where each displayed variations will be sorted by regular price (low to high):
add_shortcode("price_variation_table", "custom_available_variations_table");
function custom_available_variations_table( $atts ) {
global $post;
// Attributes
$atts = shortcode_atts(
array(
'id' => $post->ID
),
$atts, 'price_variation_table'
);
if( is_admin() ) return; // Only on front end
$product = wc_get_product($atts['id']); // Get the WC_Product Object
$output = '<div class="fs-product-data-wrapper">';
// Variable products
if( $product->is_type('variable'))
{
// Get available variations in the variable product
$available_variations = $product->get_available_variations();
if( count($available_variations) > 0 ){
$variations_ids = array();
// First loop - set variations Ids in an array with regular prices
foreach( $available_variations as $variation ){
$product = wc_get_product( $variation['variation_id'] );
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$variations_ids[$variation['variation_id']] = $price;
}
// Sorting variation Ids using prices from lower to highest
natsort($variations_ids);
// 2nd Loop - Display formatted variation data
foreach( array_keys($variations_ids) as $variations_id ){
$output .= format_product_data_output( $variations_id );
}
}
}
// Simple products
elseif( $product->is_type('simple'))
{
$output .= format_product_data_output( $product->get_id() );
}
else return; // Exit
return $output .= '</div>'; // return always for a shortcode
}
// Utility funtion: getting and formatting product data
function format_product_data_output( $the_id ){
$empty = __( '<em>(empty)</em>', 'woocommerce' );
// Get an instance of the WC_Product_Variation object
$product = wc_get_product( $the_id );
// Only wc_get_price_to_display() respect if product is to be displayed with or without including taxes
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$sale_price = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
$sale_price = ! empty( $sale_price ) ? wc_price($sale_price) : $empty;
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$no_sale_price = ! $product->is_on_sale() ? ' no-sale-price' : '';
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$stock_qty = $product->get_stock_quantity();
$stock_qty = ! empty( $stock_qty ) ? $stock_qty : '0';
$stock_status = $stock_qty <= 0 ? 'stock-sold-out' : 'stock-available';
$output = '
<ul class="'. $stock_status .'">
<li class="fs-data-price">'.$price.' ea.</li>
<li class="fs-data-size">Size: '.$size.'</li>
<li class="fs-data-sale'. $no_sale_price .'">'.$sale_price.' ea. Preferred customer price</li>
<li class="fs-data-stock">Quantity in Stock: '.$stock_qty.'</li>
<li class="fs-data-notice">Quantities change quickly!</li>
</ul>';
return $output;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I'm trying to create an order programmatically. Using wc_create_order() this is pretty straightforward:
$myProduct = new WC_Product(100);
$order = wc_create_order();
$order->add_product($myProduct, 1);
$order->calculate_totals();
This works as expected, and an order is created for a simple product with ID 100 for the correct amount.
However, if I try to do this with a variation, it doesn't seem to behave correctly. After much trial and error, I got it to sort-of work this way:
$membershipProduct = new WC_Product_Variable(100);
$theMemberships = $membershipProduct->get_available_variations();
$trueProduct = new WC_Product(100);
$variationsArray = array();
foreach ($theMemberships as $membership) {
if ($membership['sku'] == $chosenVariation) {
$variationID = $membership['variation_id'];
$variationsArray = $membership['attributes'];
}
}
if ($variationID) {
$trueProduct->variation_id = $variationID;
}
$order = wc_create_order();
$order->add_product($trueProduct, 1, $variationsArray);
$order->calculate_totals();
However, although it does create the order with the correct product and the correct variation ID, the total for the order is always 0 (which, coincidentally, is the price of the first variation).
Originally I was trying $order->add_product() with the object created from new WC_Product_Variable(), but that resulted in no products being added to the order at all, which leads me to believe it's an issue with creating orders programmatically with variable products. However, following the WooCommerce source code for these calls, I can't see what I'm doing wrong.
Is there something I'm missing, or a better way to create an order with a variable product?
Solved it.
Even though I could have sworn I'd tried (and failed) doing it this way, the answer was to not add the parent product ($trueProduct in the example), but to add the variation product by its ID.
This may have failed previously because, as #helgatheviking noted, my $variationsArray was formatted incorrectly according to the source; I needed an array with a ['variation'] key to send the correct variation array of attributes.
In total, my working code now looks like this:
$membershipProduct = new WC_Product_Variable(100);
$theMemberships = $membershipProduct->get_available_variations();
$variationsArray = array();
foreach ($theMemberships as $membership) {
if ($membership['sku'] == $chosenVariation) {
$variationID = $membership['variation_id'];
$variationsArray['variation'] = $membership['attributes'];
}
}
if ($variationID) {
$varProduct = new WC_Product_Variation($variationID);
$order = wc_create_order();
$order->add_product($varProduct, 1, $variationsArray);
$order->calculate_totals();
}
if you already have the variation_id you can just do this
$product_variation = new WC_Product_Variation($variation_id);
$order = wc_create_order();
$args=array();
foreach($product_variation->get_variation_attributes() as $attribute=>$attribute_value){
$args['variation'][$attribute]=$attribute_value;
}
$order->add_product($product_variation, $product['quantity'], $args);
Here is the solution that worked for me:
function add_item_to_order( $order_id, $prod_id ) {
$order = wc_get_order( $order_id );
$_product = wc_get_product( $prod_id );
// Set values
$item = array();
$item['product_id'] = $_product->id;
$item['variation_id'] = isset( $_product->variation_id ) ? $_product->variation_id : '';
$item['variation_data'] = $item['variation_id'] ? $_product->get_variation_attributes() : '';
$item['name'] = $_product->get_title();
$item['tax_class'] = $_product->get_tax_class();
$item['qty'] = 1;
$item['line_subtotal'] = wc_format_decimal( $_product->get_price_excluding_tax() );
$item['line_subtotal_tax'] = '';
$item['line_total'] = wc_format_decimal( $_product->get_price_excluding_tax() );
$item['line_tax'] = '';
$item['type'] = 'line_item';
// Add line item
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $item['name'],
'order_item_type' => 'line_item'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, '_qty', $item['qty'] );
wc_add_order_item_meta( $item_id, '_tax_class', $item['tax_class'] );
wc_add_order_item_meta( $item_id, '_product_id', $item['product_id'] );
wc_add_order_item_meta( $item_id, '_variation_id', $item['variation_id'] );
wc_add_order_item_meta( $item_id, '_line_subtotal', $item['line_subtotal'] );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', $item['line_subtotal_tax'] );
wc_add_order_item_meta( $item_id, '_line_total', $item['line_total'] );
wc_add_order_item_meta( $item_id, '_line_tax', $item['line_tax'] );
wc_add_order_item_meta( $item_id, '_line_tax_data', array(
'total' => array(),
'subtotal' => array() )
);
// Store variation data in meta
if ( $item['variation_data'] && is_array( $item['variation_data'] ) ) {
foreach ( $item['variation_data'] as $key => $value ) {
wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
}
}
}
$item['item_meta'] = $order->get_item_meta( $item_id );
$item['item_meta_array'] = $order->get_item_meta_array( $item_id );
$item = $order->expand_item_meta( $item );
$order->calculate_totals();
}