change "out of stock" text with html element woocommerce - wordpress

i want to change the "out of stock" text with html element woocommerce.
Currently, I'm using:
add_filter( 'woocommerce_get_availability', 'change_out_of_stock_text', 1, 2);
function change_out_of_stock_text( $availability, $_product ) {
global $post;
if ( ! $_product->is_in_stock() ) {
$out_of_stock = "Out of Stock";
if(get_post_meta( $post->ID, '_text_field', true )!="") {
$out_of_stock = get_post_meta( $post->ID, '_text_field', true );
}
$availability['availability'] = __($out_of_stock, 'woocommerce');
}
return $availability;
}
It can change the "Out of Stock" text with the value from custom input field i made in product page but i want to show the html element from that value to shop page as well. For example if the value is 'Sold out', it should output the link text as well "Sold out".
I also tried woocommerce_stock_html but it got the same problem:
function change_out_of_stock_text( $html, $_availability, $_product ){
global $post;
$out_of_stock = "Out of Stock";
$_availability = $_product->get_availability();
if(get_post_meta( $post->ID, '_text_field', true )!="") {
$out_of_stock = get_post_meta( $post->ID, '_text_field', true );
}
$html = '<p class="stock ' . esc_attr( $_availability['class'] ) . '">' . $out_of_stock . '</p>';
return $html;
}
add_filter( 'woocommerce_stock_html', 'change_out_of_stock_text', 10, 3 );

Seems like you have the right idea but you are't targeting the appropriate filter which is woocommerce_get_availability
function so_34126704_availability( $array, $product ){
if ( ! $_product->is_in_stock() ) && ( $status = get_post_meta( $product->id, '_text_field', true ) ) != "" ){
$availability['availability'] = $status;
}
return $array;
}
add_filter( 'woocommerce_get_availability', 'so_34126704_availability', 10, 2 );
to filter the output html you need to filter woocommerce_stock_html. it's a bit half-baked because I don't know what you'd want to do with the classes or where you are linking to, but here's a shell example of that:
function so_34126704_availability_html( $html, $_availability, $product ){
$availability = $product->get_availability(); // for some reason the $_availability does not pass the entire array, only the availability key
$status = get_post_meta( $product->id, '_text_field', true );
$html = '<p class="stock ' . esc_attr( $availability['class'] ) . '"><a href="#somewhere"/>' . esc_html( $status ) . '</a></p>';
return $html;
}
add_filter( 'woocommerce_stock_html', 'so_34126704_availability_html', 10, 3 );

Related

programmatically serve different images for shop and category pages in woocommerce

Hi – is it possible to serve a different image, than the predefined woocommerce thumbnails for the shop and category pages in a programmatical manner? For instance a different image that shows a product detail? Without digging into the code, my guess is to add to the product-image, another field labeled product-detail-image. In this field i can choose, from the media library, the detail image for a given product. Then assign a custom-size in functions.php and finally fetch the image in the appropriate place with something like this:
$product->get_image('detail_img_size');
Thanks for any hint.
It is possible with the following steps:
add an additional image meta box, source (applause for this):
//in functions.php or plugin
add_action( 'add_meta_boxes', 'detail_image_add_metabox' );
function detail_image_add_metabox () {
add_meta_box( 'listingimagediv', __( 'Detail-Bild', 'text-domain' ), 'detail_image_metabox', 'product', 'side', 'low');//post, page, product
}
function detail_image_metabox ( $post ) {
global $content_width, $_wp_additional_image_sizes;
$image_id = get_post_meta( $post->ID, '_detail_image_id', true );
$old_content_width = $content_width;
$content_width = 254;
if ( $image_id && get_post( $image_id ) ) {
if ( ! isset( $_wp_additional_image_sizes['post-thumbnail'] ) ) {
$thumbnail_html = wp_get_attachment_image( $image_id, array( $content_width, $content_width ) );
} else {
$thumbnail_html = wp_get_attachment_image( $image_id, 'post-thumbnail' );
}
if ( ! empty( $thumbnail_html ) ) {
$content = $thumbnail_html;
$content .= '<p class="hide-if-no-js"><a href="javascript:;" id="remove_listing_image_button" >' . esc_html__( 'Entferne das Detail-Bild', 'text-domain' ) . '</a></p>';
$content .= '<input type="hidden" id="upload_listing_image" name="_product_detail_image" value="' . esc_attr( $image_id ) . '" />';
}
$content_width = $old_content_width;
} else {
$content = '<img src="" style="width:' . esc_attr( $content_width ) . 'px;height:auto;border:0;display:none;" />';
$content .= '<p class="hide-if-no-js"><a title="' . esc_attr__( 'wähle das Detail-Bild', 'text-domain' ) . '" href="javascript:;" id="upload_listing_image_button" id="set-listing-image" data-uploader_title="' . esc_attr__( 'Wähle ein Detail-Bild', 'text-domain' ) . '" data-uploader_button_text="' . esc_attr__( 'wähle das Detail-Bild', 'text-domain' ) . '">' . esc_html__( 'wähle das Detail-Bild', 'text-domain' ) . '</a></p>';
$content .= '<input type="hidden" id="upload_listing_image" name="_product_detail_image" value="" />';
}
echo $content;
}
add_action( 'save_post_product', 'detail_image_save', 10, 1 );
function detail_image_save ( $post_id ) {
//check if the image is set and not empty
if( isset( $_POST['_product_detail_image'] ) && !empty($_POST['_product_detail_image']) ) {
$image_id = (int) $_POST['_product_detail_image'];
echo $image_id;
update_post_meta( $post_id, '_detail_image_id', $image_id );
} else {
//else delete the post meta
delete_post_meta($post_id, '_detail_image_id');
}
}
This creates an image meta box on the product edit screen.
add a script that communicates with the media library:
jQuery(document).ready(function($) {
// Uploading files
var file_frame;
jQuery.fn.upload_listing_image = function( button ) {
var button_id = button.attr('id');
var field_id = button_id.replace( '_button', '' );
// If the media frame already exists, reopen it.
if ( file_frame ) {
file_frame.open();
return;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: jQuery( this ).data( 'uploader_title' ),
button: {
text: jQuery( this ).data( 'uploader_button_text' ),
},
multiple: false
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
var attachment = file_frame.state().get('selection').first().toJSON();
jQuery("#"+field_id).val(attachment.id);
jQuery("#listingimagediv img").attr('src',attachment.url);
jQuery( '#listingimagediv img' ).show();
jQuery( '#' + button_id ).attr( 'id', 'remove_listing_image_button' );
jQuery( '#remove_listing_image_button' ).text( 'enterne das Detail-Bild' );
});
// Finally, open the modal
file_frame.open();
};
jQuery('#listingimagediv').on( 'click', '#upload_listing_image_button', function( event ) {
event.preventDefault();
jQuery.fn.upload_listing_image( jQuery(this) );
});
jQuery('#listingimagediv').on( 'click', '#remove_listing_image_button', function( event ) {
event.preventDefault();
jQuery( '#upload_listing_image' ).val( '' );
jQuery( '#listingimagediv img' ).attr( 'src', '' );
jQuery( '#listingimagediv img' ).hide();
jQuery( this ).attr( 'id', 'upload_listing_image_button' );
jQuery( '#upload_listing_image_button' ).text( 'wähle das Detail-Bild' );
});
});
enqueue the script in functions.php or plugin:
//load script only for product admin
function load_admin_metabox_script() {
$current_screen = get_current_screen();
if ( $current_screen->post_type === 'product' ) {
wp_enqueue_script( 'zcustom_js', get_template_directory_uri() . '/js/image_meta_box.js', array( 'jquery' ));
}
}
add_action( 'admin_enqueue_scripts', 'load_admin_metabox_script' );
assign images to the loop running for the shop and category pages:
//in functions.php or plugin
remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
add_action( 'woocommerce_before_shop_loop_item_title', 'custom_loop_product_detail_thumbnail', 10 );
function custom_loop_product_detail_thumbnail() {
global $product;
$id = $product->get_id();
$size = 'woocommerce_thumbnail';
$detail_img_id = get_post_meta( $id , '_detail_image_id', true );
//check if image id is available and not empty
if (isset($detail_img_id) && !empty($detail_img_id)){
$detail_img = wp_get_attachment_image( $detail_img_id, $size );
echo $detail_img;
//else fallback to the original product image
} else {
$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
echo $product ? $product->get_image( $image_size ) : '';
}
}
The same is applicable for the product widget. Just alter the template content-widget-product.php by overriding it in your child theme.
<!-- get detail images-->
<?php $id = $product->get_id();
//i use a custom size
$size = 'my_small_size';
$detail_img_id = get_post_meta( $id , '_detail_image_id', true );
if (isset($detail_img_id) && !empty($detail_img_id)){
$detail_img = wp_get_attachment_image( $detail_img_id, $size );
echo $detail_img;
} else {
//if detail images are not available use the original product image
echo $product->get_image('my_small_size'); // PHPCS:Ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
?>
This method allows to use a different set of product images for the shop and category pages. It may enhance the visibility of important product features and adds visual variety, at least it does it for my project.

I want to edit the checkout field from the WooCommerce admin edit page

I have added some custom fields on the WooCommerce checkout page. I have saved the data of those fields and displayed it on the admin order page. Like picture no.1. Everything is OK.
Now I want to edit the data/text/value of this field. Like picture no.2. Like billing and shipping on the admin order page....
How can I solve it?
function display_admin_order_meta ( $order ) {
$strt= $order->get_meta('_checkout_custom_name', true );
if( ! empty( $strt) ){
$label = __( 'Phone' );
if( is_admin() ){
echo '<p><strong>' . $label . ' : </strong> ' . $strt. '</p>';
}
else {
echo '<table class="woocommerce-table"><tbody><tr>
<th>' . $label . ' : </th><td>' . $strt. '</td>
</tr></tbody></table>';
}
}
$strt= $order->get_meta('_checkout_others_address', true );
if( ! empty( $strt) ){
$label = __( 'Address' );
if( is_admin() ){ // Admin
echo '<p><strong>' . $label . ' : </strong> ' . $strt. '</p>';
}
else {
echo '<table class="woocommerce-table"><tbody><tr>
<th>' . $label . ' : </th><td>' . $strt. '</td>
</tr></tbody></table>';
}
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_admin_order_meta', 20, 1);
This is the checkout field data I created. I want to edit these like the picture above.
This is a way(customize it if needed)
Add custom billing form data input with woocommerce_admin_billing_fields filter
add_filter('woocommerce_admin_billing_fields', 'add_woocommerce_admin_billing_fields');
function add_woocommerce_admin_billing_fields($billing_fields) {
$billing_fields['_checkout_custom_name'] = array( 'label' => __('Name', 'woocommerce') );
$billing_fields['_checkout_others_address'] = array( 'label' => __('Address', 'woocommerce') );
return $billing_fields;
}
Then save custom fields like this
function cloudways_save_extra_details( $post_id, $post ){
update_post_meta( $post_id, '_checkout_custom_name', $_POST[ '_checkout_custom_name' ] ) );
update_post_meta( $post_id, '_checkout_custom_address', $_POST[ '_checkout_custom_address' ] ) );
}
add_action( 'woocommerce_process_shop_order_meta', 'cloudways_save_extra_details', 45, 2 );

If regular price is blank show only sales price in Woocommerce

Just like the title said:
How can i show only the sales price in Woocommerce if the regular price is blank?
I would go for something like:
$regular_price = get_post_meta( get_the_ID(), '_regular_price', true);
$price_sale = get_post_meta( get_the_ID(), '_sale_price', true);
if ($regular_price == '') {
echo $price_sale;
} else {
echo $regular_price;
}
add_filter( 'woocommerce_get_price_html', 'change_product_price_html', 10, 2 );
function change_product_price_html( $price_html, $product ) {
global $post;
$id = !empty( $product->get_id() ) ? $product->get_id() : $post->ID;
$regular_price = get_post_meta( $id, '_regular_price', true);
$sale_price = get_post_meta( $id, '_sale_price', true);
$price_html = ( $regular_price == '' ) ? $sale_price : $regular_price;
return $price_html;
}
Please use this code in your active theme's functions.php file .

Display Custom Post Type Metabox Data

I'm having a problem displaying metabox data in a page template wp_query. I get this error:
Notice: Array to string conversion
Here is my code:
<?php
// WP_Query arguments
$args = array (
'post_type' => array( 'portfolio' ),
'ignore_sticky_posts' => true,
'posts_per_page' => '10',
);
// The Query
$portfolio_query = new WP_Query( $args );
// The Loop
if ( $portfolio_query->have_posts() ) {
while ( $portfolio_query->have_posts() ) {
$portfolio_query->the_post();
echo '<div id="portfolio">';
echo '<div class="featured_img">';
echo '' . " " . get_the_post_thumbnail() . '';
echo '</div>';
echo '<div class="portfolio">';
echo the_title( '<h2>', '</h2>' );
echo '<p>' . the_excerpt() . '</p>';
echo '<p>' . get_post_meta( get_the_ID($post->id , 'project_metabox', false) ) . '</p>';
echo '</div>';
echo '</div>';
}
} else {
echo "<h1>There are no portfolio pieces to view.</h1>";
}
// Restore original Post Data
wp_reset_postdata(); ?>
I've tried everything. This is just the latest version of my attempts. What am I doing wrong?
UPDATE:
Alright, so I found out the metadata isn't saving. I'm not exactly sure why, but I tried fixing it, and it's not working. My fixes made it worse. Here is my code:
`
public function save_metabox( $post_id, $post ) {
// Check if it's not an autosave.
if ( wp_is_post_autosave( $post_id ) )
return;
// Sanitize user input.
$project_new_web_design = isset( $_POST[ 'project_web_design' ] ) ? 'checked' : '';
$project_new_web_development = isset( $_POST[ 'project_web_development' ] ) ? 'checked' : '';
$project_new_digital_art = isset( $_POST[ 'project_digital_art' ] ) ? 'checked' : '';
$project_new_graphic_design = isset( $_POST[ 'project_graphic_design' ] ) ? 'checked' : '';
// Update the meta field in the database.
update_post_meta( $post_id, 'project_web_design ', $project_new_web_design );
update_post_meta( $post_id, 'project_web_development ', $project_new_web_development );
update_post_meta( $post_id, 'project_digital_art ', $project_new_digital_art );
update_post_meta( $post_id, 'project_graphic_design ', $project_new_graphic_design );
}
}
I believe the issue you're having is on this line:
echo '<p>' . get_post_meta( get_the_ID($post->id , 'project_metabox', false) ) . '</p>';
You seem to have mixed get_the_ID and $post->ID together. You're also attempting to echo an array.
The third parameter of get_post_meta will determine whether the value returned is a string or an array. Use true to return a single value.
Change it to:
echo '<p>' . get_post_meta( get_the_ID(), 'project_metabox', true ) . '</p>';
On a minor note you're trying to echo functions like the_excerpt(). You'll typically find that functions starting the_ instead of get_the_ will output directly instead of returning a value. Furthermore the_excerpt() will automatically add paragraph tags.
Replace this:
echo '<p>' . the_excerpt() . '</p>';
With this:
the_excerpt();

Woocommerce product variation based on user role

I've set up Woocommerce with variable products.
These products all have variations on an attribute with the possible values of 1kg, 2kg, and 5kg.
I've also created an "Aziende" user group. I want some product variations to only display for "Aziende" customers. I don't want these variations visible to other customers.
For example: Aziende Customers see the options "1kg, 2kg, 5kg", While other customer roles only see the 1kg option.
Is this possible in Woocommerce?
Yes. If you override the file woocommerce/templates/single-product/add-to-cart/variable.php you find the code for the variations selectbox.
There you could do something like:
First of all I always include this snippet when working with roles:
function user_has_role( $role, $user_id = null ) {
if ( is_numeric( $user_id ) )
$user = get_userdata( $user_id );
else
$user = wp_get_current_user();
if ( empty( $user ) )
return false;
return in_array( $role, (array) $user->roles );
}
So it can be used as:
if(user_has_role("Aziende")){
//do stuff
}
Now having this function, and knowing which template to change you should be able to do something in that file. It could be along this:
// Get terms if this is a taxonomy - ordered
if ( taxonomy_exists( $name ) ) {
$terms = wc_get_product_terms( $post->ID, $name, array( 'fields' => 'all' ) );
foreach ( $terms as $term ) {
if ( ! in_array( $term->slug, $options ) ) {
continue;
}
if($name == 'pa_weight' && $term->slug != '1kg' ) { // or whatever your attribute is called, and whatever the attribute term is called.
if(!user_has_role('aziende'){
continue;
}
}
echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $term->slug ), false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
}
} else {
foreach ( $options as $option ) {
if($name == 'pa_weight' && $option != '1kg' ) { // or whatever your attribute is called, and whatever the attribute term is called.
if(!user_has_role('aziende'){
continue;
}
}
echo '<option value="' . esc_attr( sanitize_title( $option ) ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $option ), false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
}
}
This code is not tested, so I dont know if it works. But it should give you a pointer in the correct direction.

Resources