connect woocommerce products to posts - wordpress

I am using woocommerce on my wordpress site.
I am selling paintings. The products are paintings.
I have a list of artists as posts. Each artist is one post.
I would like to connect the posts and products so I can show the artist's name on the painting page and the user can click on the name and it takes them to the artist post.
How do I do this?

This is an example of how to add a custom field in WooCommerce product general tab. Since artists are posts ( category is not specified ), it will collect links for all posts and place them in a dropdown. The value of this field will be visible on the single product page below the price ( you can open the content-single-product.php file in WooCommerce theme, to see the actions for single product template, and functions attached, and change the priority of woocommerce_product_artist function if you want to change the place where the link will appear ).
<?php
add_action( 'admin_init', 'woocommerce_custom_admin_init' );
function woocommerce_custom_admin_init() {
// display fields
add_action( 'woocommerce_product_options_general_product_data', 'woocommerce_add_custom_general_fields' );
// save fields
add_action( 'woocommerce_process_product_meta', 'woocommerce_save_custom_general_fields' );
}
function woocommerce_add_custom_general_fields() {
// creating post array for the options ( id => title)
$posts = array( '' => __( 'Select Artist' ) );
array_walk( get_posts( array( 'numberposts' => -1 ) ), function( $item ) use ( &$posts ) {
$posts[ $item->ID ] = $item->post_title;
} );
// creating dropdown ( woocommerce will sanitize all values )
echo '<div class="options_group">';
woocommerce_wp_select(
array(
'id' => '_artist',
'label' => __( 'Artist' ),
'options' => $posts
)
);
echo '</div>';
}
function woocommerce_save_custom_general_fields( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// validate id of artist page and save
if ( isset( $_POST['_artist'] ) ) {
$value = filter_input( INPUT_POST, '_artist', FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 0 ) ) );
update_post_meta( $post_id, '_artist', $value );
}
}
add_action( 'init', 'woocommerce_custom_init' );
function woocommerce_custom_init() {
// hook the woocommerce_product_artist function on to woocommerce_single_product_summary action ( priority 15 )
add_action( 'woocommerce_single_product_summary', 'woocommerce_product_artist', 15 );
}
function woocommerce_product_artist() {
global $post;
// get the artist page id and show in template ( if exists )
$artist_id = get_post_meta( $post->ID, '_artist', true );
if ( $artist_id ) :
?>
<div class="product-artist"><?php echo get_the_title( $artist_id ); ?></div>
<?php endif;
}
?>

Related

Create a custom field on WooCommerce checkout if product category equals x

so I'm looking to create/show a couple of custom fields on the checkout page of my WooCommerce page as long as a product with a certain category is in the cart. The values of these fields are only necessary for me to access in the order on the backend afterwards, and does not need to be added to the order e-mail confirmation to the customer.
Any pointers? If it helps things, I'm using ACF on my website.
Thanks in advance!
You need to do the following:
Detect if the existing products in cart is in your category
Add the fields on checkout if it matches your condition.
Validate and save the data
Display it on the backend.
This is already outlined on the docs, and you might want to read it:
https://woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#adding-a-custom-special-field
Here is an example function to detect if the cart contains a certain product within a defined category
// functions.php
function cat_in_cart( $cat_slug ) {
$cat_in_cart = false;
$cart = WC()->cart->get_cart();
if ( !$cart ) {
return $cat_in_cart;
}
foreach( $cart as $cart_item_key => $cart_item ) {
if ( has_term( $cat_slug, 'product_cat', $cart_item['product_id'] )) {
$cat_in_cart = true;
break;
}
}
return $cat_in_cart;
}
To add a field on checkout (Link to docs):
// functions.php
/**
* Add the field to the checkout
*/
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
if ( cat_in_cart( 'your_category_slug' ) ) {
echo '<div id="my_custom_checkout_field"><h2>' . __('My Field') . '</h2>';
woocommerce_form_field( 'my_field_name', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('Fill in this field'),
'placeholder' => __('Enter something'),
), $checkout->get_value( 'my_field_name' ));
echo '</div>';
}
}
After that, save the field on checkout:
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['my_field_name'] )
wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['my_field_name'] ) ) {
update_post_meta( $order_id, 'My Field', sanitize_text_field( $_POST['my_field_name'] ) );
}
}
Lastly, display it on the dashboard:
/**
* Display field value on the order edit page
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('My Field').':</strong> ' . get_post_meta( $order->id, 'My Field', true ) . '</p>';
}

Custom PLU field in woocommerce email [duplicate]

Is there any way I can add content from a custom product field to 'order completed' WooCommerce emails?
I have added this code to my functions.php in order to save my custom field to the product meta information.
//1.1 Display Activation Instructions field in admin
add_action('woocommerce_product_options_inventory_product_data', 'woocommerce_product_act_fields');
function woocommerce_product_act_fields(){
global $woocommerce, $post;
echo '<div class="product_custom_field">';
woocommerce_wp_text_input(
array(
'id' => '_act',
'label' => __('Activation Instructions', 'woocommerce'),
'desc_tip' => 'true',
'description' => 'Enter the Activation Instructions Link.'
)
);
echo '</div>';
}
//1.2 Save Activation Instructions field in product meta
add_action('woocommerce_process_product_meta', 'woocommerce_product_act_field_save');
function woocommerce_product_act_field_save($post_id){
$woocommerce_act_product_text_field = $_POST['_act'];
if (!empty($woocommerce_act_product_text_field))
update_post_meta($post_id, '_act', esc_attr($woocommerce_act_product_text_field));
}
I have also added this code to display a custom text on my 'order completed' woocomerce emails.
add_action( 'woocommerce_email_customer_details', 'bbloomer_add_content_specific_email', 20, 4 );
function bbloomer_add_content_specific_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' ) {
echo '<h2>Activation & Download Instructions</h2><p style="margin-bottom:35px;">Please refer to
our Activation Guides for detailed
activation and download instructions.</p>';
}
}
The above code works well and it displays the custom text for all 'order completed' emails.
But, I want to replace the URL part of the text with the custom product field data. The data is different for every product.
Thanks.
Use: get_post_meta to retrieves a post meta field for the given post ID.
//1.1 Display Activation Instructions field in admin
function woocommerce_product_act_fields() {
echo '<div class="product_custom_field">';
woocommerce_wp_text_input(
array(
'id' => '_act',
'label' => __('Activation Instructions', 'woocommerce'),
'desc_tip' => 'true',
'description' => 'Enter the Activation Instructions Link.'
)
);
echo '</div>';
}
add_action('woocommerce_product_options_inventory_product_data', 'woocommerce_product_act_fields', 10, 0 );
//1.2 Save Activation Instructions field in product meta
function woocommerce_product_act_field_save( $product ) {
if( isset($_POST['_act']) ) {
$product->update_meta_data( '_act', sanitize_text_field( $_POST['_act'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'woocommerce_product_act_field_save', 10, 1 );
//2 Add url to email
function woocommerce_product_act_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' ) {
$items = $order->get_items();
echo '<h2>Activation & Download Instructions</h2>';
foreach ( $items as $item ) {
// Get product ID
$product_id = $item->get_product_id();
// Get product name
$product_name = $item->get_name();
// Get post meta
$url = get_post_meta( $product_id, '_act', true);
if ( $url ) {
echo '<p style="margin-bottom:35px;">For ' . $product_name . ' follow these instructions</p>';
}
}
}
}
add_action( 'woocommerce_email_customer_details', 'woocommerce_product_act_email', 20, 4 );
add_action( 'woocommerce_email_customer_details', 'bbloomer_add_content_specific_email', 20, 4 );
function bbloomer_add_content_specific_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' ) {
$items = $order->get_items();
foreach ( $items as $item ) {
// Get product ID
$product_id = $item->get_product_id();
// Get post meta
$url = get_post_meta( $product_id, '_act', true );
if ( $url ) {
echo '<h2>'.$item->get_name().'Activation & Download Instructions</h2><p style="margin-bottom:35px;">Please refer to our Activation Guides for detailed activation and download instructions.</p>';
}
}
}
}
Try this code

WooCommerce custom order itemmeta display my account view order page

I created a custom field for the ecommerce admin order item meta. Everything is fine.
I would like to display the Custom Fields MetaValue on My Account's Order Details page. But nothing is being displayed. Based on Save Order item custom field in Woocommerce Admin order pages answer code, this is my attempt
function add_order_item_custom_field( $item_id, $item ) {
woocommerce_wp_text_input( array(
'id' => 'v_number'.$item_id,
'label' => __( 'V Number : ', 'ctxt' ),
'description' => __( 'Enter the title of your custom text field.', 'ctxt' ),
'desc_tip' => true,
'class' => 'v_number_class',
'value' => wc_get_order_item_meta( $item_id, '_v_number' ),
) );
}
add_action( 'woocommerce_before_order_itemmeta', 'add_order_item_custom_field', 10, 2 );
// Save the custom field value
function save_order_item_custom_field_value( $post_id, $post ){
$order = wc_get_order( $post_id );
foreach ( $order->get_items() as $item_id => $item ) {
if( isset( $_POST['v_number'.$item_id] ) ) {
$item->update_meta_data( '_v_number', sanitize_text_field( $_POST['v_number'.$item_id] ) );
$item->save();
}
}
$order->save();
}
add_action('save_post', 'save_order_item_custom_field_value' );
// Display meta my account view order page
printf (
'<p><a>V Number : <strong>' . $order->get_meta('_v_number') . '</strong></a></p>'
);
it should print your custom order meta value.
add_action( 'woocommerce_view_order', 'print_custom_order_meta' );
function print_custom_order_meta( $order_id ){
$order = wc_get_order($order_id);
foreach( $order->get_items() as $item ) {
echo 'V Number for '. $item->get_name() .' - ' . $item->get_meta( '_v_number', true ) . '<br>';
}
}
edit
for need to show metavalue after each product item you need to hook with a different action like this.
add_action('woocommerce_order_item_meta_end', 'show_order_meta', 11, 3);
function show_order_meta( $item_id, $item, $order ) {
echo '<br>V Number for '. $item->get_name() .' - ' . $item->get_meta( '_v_number', true ) . '<br>';
}

WooCommerce 4.0 custom checkout & ACF field value on email, admin order, and thank you page

I'm having a hard time printing my custom field value to the email notifications, order admin and thank you page. I've browsed through StackOverflow, tried every single answer I found but unfortunately not working and I couldn't figure out the problem:
I am trying to pass the value of the additional checkout field, it only prints the strong label with a blank value, and in the emails nothing shows, here is my code so far:
//new pickup location checkout field
add_action( 'woocommerce_before_order_notes', 'pickup_location_custom_checkout_field' );
function pickup_location_custom_checkout_field( $checkout ) {
echo '<div><h3>' . __('Pick-up location') . '</h3>';
woocommerce_form_field( 'pick_up_location', array(
'type' => 'text',
'class' => array('notes'),
'label' => __('<span style="color:red">[IMPORTANT]</span> Where should we meet you?'),
'placeholder' => __('Please enter your accomodation name or the nearest pick-up point if not accessible by car'),
'required' => true,
), $checkout->get_value( 'pick_up_location' ));
echo '</div>';
}
// Save the pickup location data to the order meta
add_action( 'woocommerce_checkout_create_order', 'pickup_location_checkout_field_update_order_meta' );
function pickup_location_checkout_field_update_order_meta( $order_id ) {
if (!empty($_POST['pick_up_location'])) {
update_post_meta( $order_id, 'Pick-up location', sanitize_text_field( $_POST['pick_up_location']));
}
}
// Display 'pickup location' on the order edit page (backend)
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'pickup_location_checkout_field_order_page', 10, 1 );
function pickup_location_checkout_field_order_page($order){
global $post_id;
$order = new WC_Order( $post_id );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
// Display 'pickup location' in "Order received" and "Order view" pages (frontend)
add_action( 'woocommerce_order_details_after_order_table', 'display_client_pickup_data_in_orders', 10 );
function display_client_pickup_data_in_orders( $order ) {
global $post_id;
$order = new WC_Order( $post_id );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
}
// Display 'pickup location data' in Email notifications
add_filter( 'woocommerce_email_order_meta_fields', 'display_client_pickup_data_in_emails', 10, 3 );
function display_client_pickup_data_in_emails( $fields, $sent_to_admin, $order ) {
$fields['Pickup Location'] = array(
'label' => __( 'Pickup Location' ),
'value' => get_post_meta( $order->get_id(), 'pick_up_location', true ),
);
return $fields;
}
No matter what I try, the code only prints the label without any value from the checkout form.
I know this question has been asked many times, but I tried every single answer for over 6 days without any luck. I also need to mention that I am using Woocommerce Bookings in this project.
Thanks for your help
[Update:] Saving and displaying ACF field in the cart, admin order, customer order, checkout, and emails.
Thanks to #7uc1f3r for the detailed explanation, his answer helped me to display the ACF field in a similar way, it is also based on This answer from #LoicTheAztec.
Displaying custom field on the product page above ATC:
// Displaying Pick-up time custom field value in single product page
add_action( 'woocommerce_before_add_to_cart_button', 'add_pickup_time_custom_field', 0 );
function add_pickup_time_custom_field() {
global $product;
//(compatibility with WC +3)
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
echo "<div class='pickup-time-atc'>";
echo "<span>Pick-up time: </span>";
echo get_field( 'pick_up_time', $product_id );
echo "</div>";
return true;
}
Displaying custom field value in single product page
Saving Pick-up time custom field into cart and session
// Saving Pick-up time custom field into cart and session
add_filter( 'woocommerce_add_cart_item_data', 'save_pickup_time_custom_field', 10, 2 );
function save_pickup_time_custom_field( $cart_item_data, $product_id ) {
$custom_field_value = get_field( 'pick_up_time', $product_id, true );
if( !empty( $custom_field_value ) )
{
$cart_item_data['pick_up_time'] = $custom_field_value;
}
return $cart_item_data;
}
Render Pick-up time custom field meta on cart and checkout
// Render Pick-up time meta on cart and checkout
add_filter( 'woocommerce_get_item_data', 'render_pickuptime_meta_on_cart_and_checkout', 10, 2 );
function render_pickuptime_meta_on_cart_and_checkout( $cart_data, $cart_item ) {
$custom_items = array();
// Woo 2.4.2 updates
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['pick_up_time'] ) ) {
$custom_items[] = array( "name" => "Pickup time", "value" => $cart_item['pick_up_time'] );
}
return $custom_items;
}
Render custom field meta on cart and checkout
Add custom field meta to order admin details
// Add pickup time custom field meta to order admin
add_action( 'woocommerce_checkout_create_order_line_item', 'pickuptime_checkout_create_order_line_item', 10, 4 );
function pickuptime_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if( isset( $values['pick_up_time'] ) ) {
$item->add_meta_data(
__( 'Pickup time' ),
$values['pick_up_time'],
true
);
}
}
Add custom field meta to order admin details
Add pickup time custom field meta to emails
// Add pickup time custom field meta to emails
add_filter( 'woocommerce_order_item_name', 'pickuptime_order_item_emails', 10, 2 );
function pickuptime_order_item_emails( $product_name, $item ) {
if( isset( $item['pick_up_time'] ) ) {
$product_name .= sprintf(
'<ul"><li>%s: %s</li></ul>',
__( '<span style="color:red !important">Pickup time</span>' ),
esc_html( $item['pick_up_time'] )
);
}
return $product_name;
}
Add pickup time custom field meta to emails
Please comment if you see any errors or ways to improve,
Thanks.
Woocommerce 4.0.0 and Wordpress 5.3.2
Go through your code step by step
update_post_meta( $order_id, 'Pick-up location', sanitize_text_field( $_POST['pick_up_location']));
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
'value' => get_post_meta( $order->get_id(), 'pick_up_location', true ),
You use Pick-up location, _pick_up_location & pick_up_location as meta_key
while this should be 3x the same value.
You also miss a closing tag by pickup_location_checkout_field_order_page function.
You also use wrong parameters with some hooks, etc..
Try this instead
//new pickup location checkout field
add_action( 'woocommerce_before_order_notes', 'pickup_location_custom_checkout_field' );
function pickup_location_custom_checkout_field( $checkout ) {
echo '<div><h3>' . __('Pick-up location') . '</h3>';
woocommerce_form_field( 'pick_up_location', array(
'type' => 'text',
'class' => array('notes'),
'label' => __('<span style="color:red">[IMPORTANT]</span> Where should we meet you?'),
'placeholder' => __('Please enter your accomodation name or the nearest pick-up point if not accessible by car'),
'required' => true,
), $checkout->get_value( 'pick_up_location' ));
echo '</div>';
}
// Save the pickup location data to the order meta
add_action( 'woocommerce_checkout_create_order', 'pickup_location_checkout_field_update_order_meta', 10, 2 );
function pickup_location_checkout_field_update_order_meta( $order, $data ) {
if ( !empty( $_POST['pick_up_location']) ) {
$order->update_meta_data( '_pick_up_location', sanitize_text_field( $_POST['pick_up_location'] ) ); // Order meta data
}
}
// Display 'pickup location' on the order edit page (backend)
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'pickup_location_checkout_field_order_page', 10, 1 );
function pickup_location_checkout_field_order_page( $order ) {
$pick_up_location = $order->get_meta( '_pick_up_location' );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . $pick_up_location . '</p>';
}
// Display 'pickup location' in "Order received" and "Order view" pages (frontend)
add_action( 'woocommerce_order_details_after_order_table', 'display_client_pickup_data_in_orders', 10 );
function display_client_pickup_data_in_orders( $order ) {
$pick_up_location = $order->get_meta( '_pick_up_location' );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . $pick_up_location . '</p>';
}
// Display 'pickup location data' in Email notifications
add_filter( 'woocommerce_email_order_meta_fields', 'display_client_pickup_data_in_emails', 10, 3 );
function display_client_pickup_data_in_emails( $fields, $sent_to_admin, $order ) {
$fields['Pickup Location'] = array(
'label' => __( 'Pickup Location' ),
'value' => $order->get_meta( '_pick_up_location' ),
);
return $fields;
}

Custom Field created in add_meta_boxes reappearing itself again in the default Custom Metabox

I succeed in creating a metabox with custom field inside, and I restrict it to appear in a custom post type.
//define metabox
function product_info_en() {
add_meta_box( 'english_info', 'English Info', 'english_product_name_callback', array('product'), 'normal', 'high' );
}
//add to hook
add_action( 'add_meta_boxes', 'product_info_en' );
The code to display it in the product page:
// display in add product admin page
function english_product_name_callback( $post ) {
//ob_start();
$content = esc_attr( get_post_meta( get_the_ID(), 'product_desc_en', true ) );
//here goes the custom field
echo '<fieldset><div><label><b>English Product Name:</b></label><br/>';
echo '<input id="product_name_en" type="text" name="product_name_en" style="width:100%; margin:10px 0px"';
echo ' value="';
echo esc_attr( get_post_meta( get_the_ID(), 'product_desc_en', true ) );
echo '"></div></fieldset>';
//here goes the wp_editor
echo '<fieldset><div><label><b>English Product Content Info:</b></label><div><br/>';
echo '<div>';
wp_editor($content, 'product_desc_en', array(
'wpautop' => true,
'media_buttons' => true,
'textarea_rows' => 10
)
);
echo '</div></fieldset>';
}
Here goes the code that do the saving job:
//save
function enginfo_save_meta_box( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( $parent_id = wp_is_post_revision( $post_id ) ) {
$post_id = $parent_id;
}
$fields = [
'product_name_en',
];
foreach ( $fields as $field ) {
if ( array_key_exists( $field, $_POST ) ) {
update_post_meta( $post_id, $field, sanitize_text_field( $_POST[$field] ) );
}
}
update_post_meta( $post_id,'product_desc_en', wp_kses_post( $_POST['product_desc_en'] ) );
}
add_action( 'save_post', 'enginfo_save_meta_box' );
However, the custom created field that supposed to be going only into the newly created metabox, will always show up in the default "custom field". And this happens to all post type.
As shown below, What could possibly be the issue here?
To hide and not show your custom fields there in default box, please prefix your custom fields with underscore _ , so product_desc_en will become _product_des_en
I mean the names of your custom fields should be prefixed with underscore and WordPress default custom metabox will ignore them and not show in WordPress default GUI, but you can use and display them in your own custom metaboxes by calling with there new Underscore prefixed names.

Resources