• Resolved gerd.neumann

    (@gerdneumann)


    I’ve added a custom product field “Bio”. Bio means “organic” in german.

    I followed the documentation at http://www.remicorson.com/mastering-woocommerce-products-custom-fields/

    Adding and Saving the “Bio?” boolean checkbox is done with:

    // Add Fields
    add_action( 'woocommerce_product_options_general_product_data', 'fr_add_bio_field' );
    
    function fr_add_bio_field() {
      global $woocommerce, $post;
    
      woocommerce_wp_checkbox(
        array(
          'id'          => '_fr_bio_checkbox',
          'label'       => __( 'Bio?', 'woocommerce' ),
          'desc_tip'    => 'true',
          'description' => __( 'Aktivieren, wenn Bio-Artikel. Wird dann so auf PDF-Rechnung ausgezeichnet.', 'woocommerce' )
        )
      );
    
    }
    
    // Save Fields
    add_action( 'woocommerce_process_product_meta', 'fr_add_bio_field_save' );
    function fr_add_bio_field_save( $post_id ){
        $bio_checkbox = $_POST['_fr_bio_checkbox'];
        if ( !empty( $bio_checkbox) ) {
          update_post_meta( $post_id, '_fr_bio_checkbox', esc_attr( $bio_checkbox ) );
        } else {
          delete_post_meta( $post_id, '_fr_bio_checkbox' );
        }
    }

    I can now check whether the “Bio” checkbox is set in the invoice.php with
    <?php if (fr_sku_is_bio($item['sku'])) { echo 'Biozertifiziert nach DE-Γ–ko-039'; } ?>

    and calling:

    // Called from invoice.php in woocommerce/pdf/MyCustomModern
    function fr_sku_is_bio( $sku ) {
      $product_id = wc_get_product_id_by_sku($sku);
      return fr_is_bio( $product_id );
    }
    
    function fr_is_bio( $product_id ) {
      $bio_checkbox = get_post_meta( $product_id, '_fr_bio_checkbox', true );
      if ($bio_checkbox) {
        return true;
      }
      return false;
    }

    Problem with this approach is that this always checks against the current product value of “Bio”. But I would need to check against the value that “Bio” was set to, when the order was made. Because the “Organic certificate” was only just allowed to be used and using this code, also the items from orders from the past would be “Bio” (although these are just currently on product level, but are not on order item’s level).

    I’ve seen the custom hook wpo_wcpdf_order_item_data.

    Does anybody know how I can store custom data (here just a boolean “Bio”) on a order item? Like $item['tax_class'] or $item['qty'] is store, but just $item['my_custom_bio']?

    https://ww.wp.xz.cn/plugins/woocommerce-pdf-invoices-packing-slips/

Viewing 9 replies - 1 through 9 (of 9 total)
  • Plugin Contributor Ewout

    (@pomegranate)

    Hi!
    This is somewhat beyond the support of the free plugin (it’s more of a WooCommerce issue/question), but you can copy the value to the order item meta at checkout, when the order is created (in functions.php):

    add_action('woocommerce_checkout_order_processed', 'wpo_wcpdf_copy_bio_setting');
    function wpo_wcpdf_create_invoice_number ( $order_id ) {
    	// get order then items
    	$order = wc_get_order( $order_id );
    	$items = $order->get_items();
    
    	if (empty($items)) {
    		return; // nothing to do
    	}
    
    	// loop through items to check for bio setting
    	foreach ($items as $item_id => $item) {
    		// get product
    		$product = $order->get_product_from_item( $item );
    		if (empty($product)) {
    			continue;
    		}
    
    		// get checkbox setting for product (you can use get_post_meta on $product->id too if you prefer)
    		$bio = $product->fr_bio_checkbox;
    		if (!empty($bio)) {
    			// copy value to order item meta
    			wc_add_order_item_meta( $item_id, 'fr_bio_checkbox', 'Yes' );
    		}
    	}
    }

    Then you can retrieve the value with

    $bio = wc_add_order_item_meta( $item_id, 'fr_bio_checkbox' );

    Or in with the premium templates extension you can simply add a column/block of the type ‘Item meta (single)’ in the customizer, and it will show ‘Yes’ for the items that are bio (then you can leave the template files alone).
    I noticed your template is named “MyCustomModern”, so I wasn’t sure if you’re actually using the premium templates – if so let me know!

    Hope that helps!
    Ewout

    Plugin Contributor Ewout

    (@pomegranate)

    Whoops! Made a small mistake there!

    function wpo_wcpdf_create_invoice_number ( $order_id ) {

    should be:

    function wpo_wcpdf_copy_bio_setting ( $order_id ) {

    Thread Starter gerd.neumann

    (@gerdneumann)

    Thanks for answering, very much appreciated!

    The problem with the wc_add_order_item_meta approach is that item meta data is always displayed to the user in the form key: value, e.g. on the order overview page or in the order emails. But I only need it to print a few special sentences (conditionally) on the invoice pdf.

    Is there no other way to store custom item data (like $item['bio'])? (If so, then it seems like a strange limitation of the WooCommerce API to me.)

    Plugin Contributor Ewout

    (@pomegranate)

    oh but you can easily hide meta. Items have lots more meta that you and the customer don’t see πŸ™‚ (this is not related to the WooCommerce API though, which is just an interface with the WooCommerce functions). Any item meta with a leading underscore will never be shown to the customer though, just on the backend. To hide it on the backend too you can use a filter:

    add_filter( 'woocommerce_hidden_order_itemmeta', 'woocommerce_hide_custom_itemmeta' );
    function woocommerce_hide_custom_itemmeta( $hidden_keys ) {
    	$hidden_keys[] = '_fr_bio_checkbox';
    	return $hidden_keys;
    }

    I see I made another mistake, with the retrieval (should be get instead of add).

    Full code:

    add_action('woocommerce_checkout_order_processed', 'wpo_wcpdf_copy_bio_setting');
    function wpo_wcpdf_copy_bio_setting ( $order_id ) {
    	// get order then items
    	$order = wc_get_order( $order_id );
    	$items = $order->get_items();
    
    	if (empty($items)) {
    		return; // nothing to do
    	}
    
    	// loop through items to check for bio setting
    	foreach ($items as $item_id => $item) {
    		// get product
    		$product = $order->get_product_from_item( $item );
    		if (empty($product)) {
    			continue;
    		}
    
    		// get checkbox setting for product (you can use get_post_meta on $product->id too if you prefer)
    		$bio = $product->fr_bio_checkbox;
    		if (!empty($bio)) {
    			// copy value to order item meta
    			wc_add_order_item_meta( $item_id, '_fr_bio_checkbox', 'Yes' );
    		}
    	}
    }

    retrieval:

    $bio = wc_get_order_item_meta( $item_id, '_fr_bio_checkbox' );

    Thread Starter gerd.neumann

    (@gerdneumann)

    Thanks, I did not know about the underscore for hiding meta data.

    Thread Starter gerd.neumann

    (@gerdneumann)

    Plugin Contributor Ewout

    (@pomegranate)

    why do you think it is better?

    Thread Starter gerd.neumann

    (@gerdneumann)

    Seems more appropriate/specific.

    Like the comment above it says “Allow plugins to add order item meta”, so woocommerce_add_order_item_meta for adding custom order item meta. Params are $item_id, $values, $cart_item_key. So I can just do $values[_fr_bio_checkbox] = true.

    Obviously one can do the same with woocommerce_checkout_order_processed which is more generell. So it seems to need more code to iterate over all items.

    I am also not sure, whether woocommerce_checkout_order_processed is also called for manual added orders (which has no checkout AFAIU). Whereas woocommerce_add_order_item_meta is called as part of the create_order function.

    Please correct me if I am wrong. I am just infering from looking at the code and the stackoverflow answer, have no real practical experience here.

    Plugin Contributor Ewout

    (@pomegranate)

    Good point – it makes the code much more simple.

    Both hooks only ever execute after checkout (basically converting the cart into an order). The advantage of using woocommerce_checkout_order_processed over woocommerce_add_order_item_meta is that the latter is executed when the totals of the order and other stuff has not been set. Basically with the woocommerce_checkout_order_processed hook you have a finished order you can work with, which is why it’s my go-to hook for this kind of stuff. In this particular case that’s not relevant, so I would indeed use woocommerce_add_order_item_meta.
    Thanks for bringing this up!

    Ewout

Viewing 9 replies - 1 through 9 (of 9 total)

The topic ‘Store custom boolean data in $item of order’ is closed to new replies.