I added a custom subtitle field for woo-commerce products. When I fill its field from the dashboard it appears in the product. I can update the text but I can't remove its value it appears again when I update the product.
Here the code. I copied from somewhere
<?php
// Display Fields
add_action('woocommerce_product_options_general_product_data',
'woocommerce_product_custom_fields');
// Save Fields
add_action('woocommerce_process_product_meta', 'woocommerce_product_custom_fields_save');
function woocommerce_product_custom_fields()
{
global $woocommerce, $post;
echo '<div class="product_custom_field">';
// Custom Product Text Field
woocommerce_wp_text_input(
array(
'id' => '_custom_product_subtitle',
'placeholder' => 'Custom Product Subtitle',
'label' => __('Custom Product Subtitle', 'woocommerce'),
'desc_tip' => 'true'
)
);
}
function woocommerce_product_custom_fields_save($post_id)
{
// Custom Product Text Field
$woocommerce_custom_product_text_field = $_POST['_custom_product_subtitle'];
if (!empty($woocommerce_custom_product_text_field))
update_post_meta($post_id, '_custom_product_subtitle',
esc_attr($woocommerce_custom_product_text_field));
}
// To show after the title
add_action( 'woocommerce_after_shop_loop_item_title', 'custom_field_display_below_title', 2 );
function custom_field_display_below_title(){
global $product;
// Get the custom field value
$custom_field = get_post_meta( $product->get_id(), '_custom_product_subtitle', true );
// Display
if( ! empty($custom_field) ){
echo '<p class="custom-product-subtitle">'.$custom_field.'</p>';
}
}
This is the result of the code, it also displays where I want to, but I can't make remove the text it appears again when I update
To be able to reset (empty) this custom field, just replace the code line (from your 2nd function):
if( ! empty($woocommerce_custom_product_text_field) ){
by:
if( isset($woocommerce_custom_product_text_field) ){
So now you can remove the field value and save it.
Now since WooCommerce 3, your code is a bit outdated… Also, you should use shorter keys and variable names.
Below is your revisited code (changed the field meta key from '_custom_product_subtitle' to simply '_subtitle', replaced a hook and made some other changes).
// Display a text Field (admin single product)
add_action( 'woocommerce_product_options_general_product_data', 'display_admin_product_custom_text_field' );
function woocommerce_product_custom_fields() {
echo '<div class="product_custom_field">';
woocommerce_wp_text_input( array(
'id' => '_subtitle',
'label' => __('Custom subtitle', 'woocommerce'),
'placeholder' => __('You can add optionally a custom subtitle', 'woocommerce'),
'desc_tip' => 'true'
) );
echo '</div>'; // <== missing
}
// Save Text Field value (admin)
add_action( 'woocommerce_admin_process_product_object', 'save_admin_product_custom_text_field_value' );
function save_admin_product_custom_text_field_value( $product ) {
if ( isset($_POST['_subtitle']) ) {
$product->update_meta_data( '_subtitle', sanitize_text_field($_POST['_subtitle']) );
}
}
// Display product subtitle (front end)
add_action( 'woocommerce_after_shop_loop_item_title', 'custom_field_display_below_title', 2 );
function custom_field_display_below_title(){
global $product;
$value = $product->get_meta('_subtitle'); // Get the custom field value
if( ! empty($value) ){
echo '<p class="product-subtitle">' . $value . '</p>'; // Display
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Related
I have a problem with the code below. With that code, we can select specific product and give them a different style in the shop archive. This is working.
However, I guess there is a error in the code.
Once I activated the checkbox for a product, it always appears in the new style even when I uncheck the checkbox. I assume that I made a error with the get_post_meta object.
Can someone help me with that?
Code to display the check box in the general product settings and add the class, based on the value in the check box
// Add checkbox
function action_woocommerce_product_general_options_product_style_listing_data() {
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_special_product_listing_style', // Required, it's the meta_key for storing the value (is checked or not)
'label' => __( 'Special style', 'woocommerce' ), // Text in the editor label
'desc_tip' => false, // true or false, show description directly or as tooltip
'description' => __( 'Promote a product by changing the style of the product card', 'woocommerce' ) // Provide something useful here
) );
}
add_action( 'woocommerce_product_options_general_product_data', 'action_woocommerce_product_general_options_product_style_listing_data', 10, 0 );
// Save Field
function action_woocommerce_product_general_options_product_style_listing_save( $product ) {
// Isset, yes or no
$checkbox = isset( $_POST['_special_product_listing_style'] ) ? 'yes' : 'no';
// Update meta
$product->update_meta_data( '_special_product_listing_style', $checkbox );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_product_general_options_product_style_listing_save', 10, 1 );
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
if ( get_post_meta( $product->get_id(), '_special_product_listing_style', true ) ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
CSS to style the specific products:
/* Custom special product listing style */
li.sales-flash-overlay.woocommerce-text-align-left.woocommerce-image-align-center.do-quantity-buttons.product.type-product.post-10800.status-publish.first.instock.product_cat-crafty-beer-club.has-post-thumbnail.featured.sold-individually.taxable.shipping-taxable.product-type-variable.custom-product-listing-class {
border: 2px solid;
border-style: dashed;
}
Replace
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
if ( get_post_meta( $product->get_id(), '_special_product_listing_style', true ) ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
With
// Is_special style
function filter_woocommerce_post_class( $classes, $product ) {
// Get meta
$spls = $product->get_meta( '_special_product_listing_style' );
// Compare
if ( $spls == 'yes' ) {
$classes[] = 'custom-product-listing-class';
}
return $classes;
}
add_filter( 'woocommerce_post_class', 'filter_woocommerce_post_class', 10, 2 );
That should suffice for your code to function fully
I'm trying to add a custom field in the general section of a product and initialize it with a frontend form.
I had no problem in adding it, but I'm little lost on how to set it.
TO ADD AND SAVE THE CUSTOM FIELD:
// The code for displaying WooCommerce Product Custom Fields
add_action('woocommerce_product_options_general_product_data', 'woocommerce_product_custom_fields');
// Following code Saves WooCommerce Product Custom Fields
add_action('woocommerce_process_product_meta', 'woocommerce_product_custom_fields_save');
function woocommerce_product_custom_fields()
{
global $woocommerce, $post;
echo '<div class=" product_custom_field ">';
//Custom Product Text Field
woocommerce_wp_text_input(
array(
'id' => 'tipologiaAppunto',
'label' => __('Tipologia appunto:', 'woocommerce'),
'placeholder' => '',
'desc_tip' => 'true'
)
);
echo '</div>';
}
function woocommerce_product_custom_fields_save($post_id)
{
// Custom Product Text Field
$woocommerce_custom_product_text_field = $_POST['tipologiaAppunto'];
if (!empty($woocommerce_custom_product_text_field))
update_post_meta($post_id, 'tipologiaAppunto', esc_attr($woocommerce_custom_product_text_field));
}
To set it I've tried to extend the WC_PRODUCT CLASS
EXTENSION OF THE WC_PRODUCT CLASS:
add_action('init', 'register_myclass');
function register_myclass()
{
class WC_ProductExtended extends WC_Product
{
function __construct() {
parent::__construct();
if (!array_key_exists("tipologiaAppunto", $this->data)) {
$this->data["tipologiaAppunto"] = "";
}
}
/**
* Set product tipologiaAppunto.
*
* #since 3.0.0
* #param string $tipologiaAppunto Product tipologiaAppunto.
*/
public function set_tipologiaAppunto($tipologiaAppunto)
{
$this->set_prop( 'tipologiaAppunto', $tipologiaAppunto );
}
}
}
And now by calling the setter I was hoping to initialize the product custom field, but nothing happened.
$product->set_regular_price($_POST['price']);
$productExtendend = new WC_ProductExtended();
$productExtendend->set_tipologiaAppunto("Hey");
$productExtendend->save();
I don't know If this is the right I way, I found a lot of tutorial on how to add the custom field but so little on how to initialize it from the frontend, I've tried by mimic the behaviour of the existing fields but with no luck.
Why you don't simply use WC_Data update_meta_data() and get_meta() methods as follow:
$product->set_regular_price($_POST['price']);
$product->update_meta_data("tipologiaAppunto", "Hey"); // <== Set (or update) the custom field value from a meta key
$product->save();
echo $product->get_meta("tipologiaAppunto"); // <== Get (or read) the custom field value from a meta key
Also since Woocommerce 3, you can replace woocommerce_process_product_meta action hook, by woocommerce_admin_process_product_object so your code will be instead:
// Display admin product custom setting field(s)
add_action('woocommerce_product_options_general_product_data', 'woocommerce_product_custom_fields');
function woocommerce_product_custom_fields() {
global $product_object;
echo '<div class=" product_custom_field ">';
// Custom Product Text Field
woocommerce_wp_text_input( array(
'id' => 'tipologiaAppunto',
'label' => __('Tipologia appunto:', 'woocommerce'),
'placeholder' => '',
'desc_tip' => 'true' // <== Not needed as you don't use a description
) );
echo '</div>';
}
// Save admin product custom setting field(s) values
add_action('woocommerce_admin_process_product_object', 'woocommerce_product_custom_fields_save');
function woocommerce_product_custom_fields_save( $product ) {
if ( isset($_POST['tipologiaAppunto']) ) {
$product->update_meta_data( 'tipologiaAppunto', sanitize_text_field( $_POST['tipologiaAppunto'] ) );
}
}
I'm trying to add a custom field just below the price in my Woocommerce theme. I was able to add simple html by using:
add_action( 'woocommerce_before_add_to_cart_form', 'SomeName' );
function SomeName() {
echo '<p>Some Text Here</p>';
}
But what I want to do is add a custom field key instead. I'm using this code for placing custom fields:
<?php
$naslov = get_post_meta($post->ID, 'Naslov', true);
if ($naslov) { ?>
<h2 class="single-naslov-kat"><? echo $naslov; ?></h2>
<?php
} else {
// do nothing;
}
?>
The code works great when I add it to content-single-product.php theme file. But I can't add it below the price through that file. And I have no idea how to incorporate it through functions.php.
If you have any other suggestions on how I might be able to add custom text below the price for each specific product that's ok too.
Any help would be greatly appreciated.
In your themes functions.php add the code,
//create custom field
function cfwc_create_custom_field() {
$args = array(
'id' => 'custom_field',
'label' => __( 'Custom Field', 'cfwc' ),
'class' => 'cfwc-custom-field',
'desc_tip' => true,
'description' => __( 'Enter Custom Field Description.', 'ctwc' ),
);
woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_general_product_data', 'cfwc_create_custom_field' );
// save custom field
function cfwc_save_custom_field( $post_id ) {
$link = wc_get_product( $post_id );
$title = isset( $_POST['custom_field'] ) ? $_POST['custom_field'] : '';
$link->update_meta_data( 'custom_field', sanitize_text_field( $title ) );
$link->save();
}
add_action( 'woocommerce_process_product_meta', 'cfwc_save_custom_field' );
// display custom field in single.php page
add_action('woocommerce_before_add_to_cart_form','cmk_additional_button');
function cmk_additional_button() {
global $product;
$custom_field = $product->get_meta('custom_field');
if(!empty($custom_field)) {
echo "<a href='$custom_field' target='_blank'><button type='button' class='button alt'>Custom Field</button></a>";
}
}
I'm trying to disable adding to cart certain products which have the "Call to Order" checkbox ticked (see code below) on the product editor.
add_action( 'woocommerce_product_options_general_product_data', 'custom_general_product_data_custom_fields' );
/**
* Add `Call to Order` field in the Product data's General tab.
*/
function custom_general_product_data_custom_fields() {
// Checkbox.
woocommerce_wp_checkbox(
array(
'id' => '_not_ready_to_sell',
'wrapper_class' => 'show_if_simple',
'label' => __( 'Call to Order', 'woocommerce' ),
'description' => __( '', 'woocommerce' )
)
);
}
add_action( 'woocommerce_process_product_meta', 'custom_save_general_proddata_custom_fields' );
/**
* Save the data values from the custom fields.
* #param int $post_id ID of the current product.
*/
function custom_save_general_proddata_custom_fields( $post_id ) {
// Checkbox.
$woocommerce_checkbox = isset( $_POST['_not_ready_to_sell'] ) ? 'yes' : 'no';
update_post_meta( $post_id, '_not_ready_to_sell', $woocommerce_checkbox );
}
add_filter( 'woocommerce_is_purchasable', 'custom_woocommerce_set_purchasable', 10, 2);
/**
* Mark "Not ready to sell" products as not purchasable.
*/
function custom_woocommerce_set_purchasable() {
$not_ready_to_sell = get_post_meta( get_the_ID(), '_not_ready_to_sell' , true);
return ( 'yes' == $not_ready_to_sell ? false : true );
}
add_filter( 'woocommerce_product_add_to_cart_text', 'custom_product_add_to_cart_text' );
/**
* Change "Read More" button text for non-purchasable products.
*/
function custom_product_add_to_cart_text() {
$not_ready_to_sell = get_post_meta( get_the_ID(), '_not_ready_to_sell', true );
if ( 'yes' === $not_ready_to_sell ) {
return __( 'Call to Order', 'woocommerce' );
} else {
return __( 'Add to Cart', 'woocommerce' );
}
}
The products that have the checkbox ticked, are in fact not purchasable, which is the desired outcome.
The problem I'm having is when I click "Add to Cart" for purchasable products (those without the checkbox ticked) on the product catalog page, I am redirected to the product page and a default WooCommerce message "Sorry, this product cannot be purchased." appears. What should be happening is that when the "Add to Cart" button is clicked, the product is automatically added to the cart.
Also from the single product page, I can add the purchasable cart without a problem.
I am not sure why this is happening this way. Any ideas?
I have tested your code and it work without problems… I don't have the problematic behavior you describe… So something else is making trouble:
You will need first to make a database backup… Then you should try to:
Check if in your other customizations, there is something that is disabling Ajax add to cart and making that message appear. Try to comment your other customizations to find the guilty one.
Try to disable all third party plugins related to Woocommerce (except Woocommerce). If the problem is gone, re-enable them one by one to find the guilty.
The problem could come from the theme too.
Now since Woocommerce 3 and introduced CRUD Objects, your code is a bit outdated.
Here is revisited and enhanced code version (for Woocommerce 3+):
// Add a custom field in the Product data's General tab (for simple products).
add_action( 'woocommerce_product_options_general_product_data', 'add_general_product_data_custom_field' );
function add_general_product_data_custom_field() {
woocommerce_wp_checkbox( array( // Checkbox.
'id' => '_not_ready_to_sell',
'label' => __( 'Call to Order', 'woocommerce' ),
'wrapper_class' => 'show_if_simple',
) );
}
// Save custom field value
add_action( 'woocommerce_admin_process_product_object', 'save_general_product_data_custom_field', 10, 1 );
function save_general_product_data_custom_field( $product ) {
$product->update_meta_data( '_not_ready_to_sell', isset( $_POST['_not_ready_to_sell'] ) ? 'yes' : 'no' );
}
// Make not purchasable, products with '_not_ready_to_sell' meta data set to "yes" (for simple products)
add_filter( 'woocommerce_is_purchasable', 'filter_woocommerce_set_purchasable', 10, 2);
function filter_woocommerce_set_purchasable( $purchasable, $product ) {
return 'yes' === $product->get_meta( '_not_ready_to_sell' ) && $product->is_type('simple') ? false : $purchasable;
}
// Change button text to "Call to Order" for simple products not purchasable.
add_filter( 'woocommerce_product_add_to_cart_text', 'filter_product_add_to_cart_text', 10, 2 );
function filter_product_add_to_cart_text( $button_text, $product ) {
if ( 'yes' === $product->get_meta( '_not_ready_to_sell' ) && $product->is_type('simple') ) {
$button_text = __( 'Call to Order', 'woocommerce' );
}
return $button_text;
}
Code goes on function.php file of your active child theme (or active theme). It could works.
I work on site that use External products from Amazon, but want instead pointing users to that external URL, first to add to cart that product. I have this function, that change Default Button text for each product, to Add to cart.
function sv_wc_external_product_button( $button_text, $product ) {
if ( 'external' === $product->get_type() ) {
// enter the default text for external products
return $product->button_text ? $product->button_text : 'Add To Cart';
}
return $button_text;
}
add_filter( 'woocommerce_product_single_add_to_cart_text',
'sv_wc_external_product_button', 10, 2 );
But this function not add product to cart.
How to make this function to Add selected product to cart?
Thanks.
Updated 2020
This is a complete different way with simple products and a custom field external link.
In this answer we will use simple products instead of external products.
We add an "External URL" custom field in product option settings and we save the data.
Add a custom field on general product option settings for simple products only :
add_action( 'woocommerce_product_options_general_product_data', 'simple_product_with_external_url' );
function simple_product_with_external_url() {
global $product_object;
echo '<div class="options_group show_if_simple hidden">';
// External Url
woocommerce_wp_text_input( array(
'id' => '_ext_url_cust',
'label' => 'External Url',
'description' => 'Custom external URL',
'desc_tip' => 'true',
'placeholder' => 'Enter here your custom external URL'
) );
echo '</div>';
}
Save the custom field data if it's a simple product and not empty:
add_action( 'woocommerce_admin_process_product_object', 'save_simple_product_with_external_url' );
function save_simple_product_with_external_url( $product ) {
if( $product->is_type('simple') && isset($_POST['_ext_url_cust']) ) {
$product->update_meta_data( '_ext_url_cust', sanitize_url($_POST['_ext_url_cust']) );
}
}
2) This will not work on shop pages and archives pages, if we don't set in WooCommerce the cart redirection when adding a product to cart.
So we will replace add-to-cart button (just for our simple products with a custom link redirection) on shop pages and archives pages by a linked custom button to single product pages.
Replacing add-to-cart button in shop pages and archives pages (for simple products with custom external url):
add_filter( 'woocommerce_loop_add_to_cart_link', 'quantity_inputs_for_woocommerce_loop_add_to_cart_link', 10, 2 );
function quantity_inputs_for_woocommerce_loop_add_to_cart_link( $html, $product ) {
$external_url = $product->get_meta('_ext_url_cust');
if ( ! empty($external_url) ) {
$html = sprintf( '%s', $product->get_permalink(), __("Read More", "woocommerce") );
}
return $html;
}
3) If the custom field value is not empty, the product is added to cart first and then redirected to the external URL (our custom field value in single product pages)
External URL redirection after adding to cart (when custom field is not empty in simple products):
add_filter( 'woocommerce_add_to_cart_redirect', 'redirect_simple_product_with_external_url' );
function redirect_simple_product_with_external_url( $url ) {
if( isset($_REQUEST['add-to-cart']) && absint( $_REQUEST['add-to-cart'] ) > 0 )
return get_post_meta( absint( $_REQUEST['add-to-cart'] ), '_ext_url_cust', true );
return $url;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce version 3+
Use https://stackoverflow.com/a/44036965/3730754 instead.
You should try to use woocommerce_product_add_to_cart_url filter hook to change the add-to-cart link (here for grouped products), this way:
add_filter( 'woocommerce_product_add_to_cart_url', 'override_external_product_url', 10, 2 );
function override_external_product_url( $url, $product ){
if ( 'external' === $product->get_type() ) {
//Get product ID -- WooCommerce compatibility
if ( method_exists( $product, 'get_id' ) ) {
$product_id = $product->get_id();
} else {
$product_id = $product->id;
}
// custom add to cart url example
$url = home_url( "/product/?add-to-cart=$product_id");
}
return $url;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Update: But this will not add to cart this external product before redirecting to an external url even if it works displaying the add-to-cart url (as add-to-cart is ajax driven).
I fixed myself. For External products, to replace default "Buy This Product" with other generic text, add this functions into functions.php file into theme:
add_filter( 'woocommerce_product_add_to_cart_text' ,
'wpf_custom_add_cart_text_archive',11);
function wpf_custom_add_cart_text_archive() {
global $product;
$product_type = $product->product_type;
switch ( $product_type ) {
case 'external':
return __( 'Add to Cart', 'woocommerce' );
break;
case 'grouped':
return __( 'View products', 'woocommerce' );
break;
case 'simple':
return __( 'Add to cart', 'woocommerce' );
break;
case 'variable':
return __( 'Select options', 'woocommerce' );
break;
default:
return __( 'Read more', 'woocommerce' );
}
}
add_filter( 'woocommerce_product_single_add_to_cart_text',
'wpf_custom_add_cart_text',11);
and this one:
function wpf_custom_add_cart_text() {
return __( 'Add to Cart', 'woocommerce' );
}
to replace text everywhere.